And*_*rew 10 javascript reactjs react-redux
我已经更新了底部的更新
有没有办法维护单一的根状态(如Redux),多个Context API使用者在自己的Provider值上工作,而不会在每次孤立的更改中触发重新呈现?
已经阅读了这个相关问题并尝试了一些变体来测试那里提供的一些见解,我仍然对如何避免重新渲染感到困惑.
完整代码如下所示:https://codesandbox.io/s/504qzw02nl
问题在于,根据devtools,每个组件都会看到"更新"(重新渲染),即使它SectionB是唯一看到任何渲染更改的组件,即使它b是状态树中唯一发生变化的部分.我已尝试使用功能组件,PureComponent并看到相同的渲染颠簸.
因为没有任何东西作为道具传递(在组件级别),我无法看到如何检测或阻止这种情况.在这种情况下,我将整个应用程序状态传递给提供程序,但我也尝试传递状态树的片段并看到相同的问题.显然,我做错了.
import React, { Component, createContext } from 'react';
const defaultState = {
a: { x: 1, y: 2, z: 3 },
b: { x: 4, y: 5, z: 6 },
incrementBX: () => { }
};
let Context = createContext(defaultState);
class App extends Component {
constructor(...args) {
super(...args);
this.state = {
...defaultState,
incrementBX: this.incrementBX.bind(this)
}
}
incrementBX() {
let { b } = this.state;
let newB = { ...b, x: b.x + 1 };
this.setState({ b: newB });
}
render() {
return (
<Context.Provider value={this.state}>
<SectionA />
<SectionB />
<SectionC />
</Context.Provider>
);
}
}
export default App;
class SectionA extends Component {
render() {
return (<Context.Consumer>{
({ a }) => <div>{a.x}</div>
}</Context.Consumer>);
}
}
class SectionB extends Component {
render() {
return (<Context.Consumer>{
({ b }) => <div>{b.x}</div>
}</Context.Consumer>);
}
}
class SectionC extends Component {
render() {
return (<Context.Consumer>{
({ incrementBX }) => <button onClick={incrementBX}>Increment a x</button>
}</Context.Consumer>);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我知道react-devtools检测或显示重新渲染的方式可能存在错误.我以一种显示问题的方式扩展了上面的代码.我现在无法判断我正在做什么实际上是否导致重新渲染.根据我从丹·阿布拉莫夫那里读到的内容,我认为我正确地使用了提供者和消费者,但我无法明确地判断这是否属实.我欢迎任何见解.
ped*_*ern 15
有一些方法可以避免重新渲染,也可以使您的状态管理“类似于 redux”。我将向您展示我一直在做的事情,它远非 redux,因为 redux 提供了许多实现起来并不那么简单的功能,例如能够从任何操作或 combineReducers 将操作分派给任何 reducer 等很多其他的。
export const initialState = {
...
};
export const reducer = (state, action) => {
...
};
Run Code Online (Sandbox Code Playgroud)
export const AppContext = React.createContext({someDefaultValue})
export function ContextProvider(props) {
const [state, dispatch] = useReducer(reducer, initialState)
const context = {
someValue: state.someValue,
someOtherValue: state.someOtherValue,
setSomeValue: input => dispatch('something'),
}
return (
<AppContext.Provider value={context}>
{props.children}
</AppContext.Provider>
);
}
Run Code Online (Sandbox Code Playgroud)
function App(props) {
...
return(
<AppContext>
...
</AppContext>
)
}
Run Code Online (Sandbox Code Playgroud)
这样,它们只会在这些特定依赖项使用新值更新时重新渲染
const MyComponent = React.memo(({
somePropFromContext,
setSomePropFromContext,
otherPropFromContext,
someRegularPropNotFromContext,
}) => {
... // regular component logic
return(
... // regular component return
)
});
Run Code Online (Sandbox Code Playgroud)
function select(){
const { someValue, otherValue, setSomeValue } = useContext(AppContext);
return {
somePropFromContext: someValue,
setSomePropFromContext: setSomeValue,
otherPropFromContext: otherValue,
}
}
Run Code Online (Sandbox Code Playgroud)
function connectToContext(WrappedComponent, select){
return function(props){
const selectors = select();
return <WrappedComponent {...selectors} {...props}/>
}
}
Run Code Online (Sandbox Code Playgroud)
import connectToContext from ...
import AppContext from ...
const MyComponent = React.memo(...
...
)
function select(){
...
}
export default connectToContext(MyComponent, select)
Run Code Online (Sandbox Code Playgroud)
<MyComponent someRegularPropNotFromContext={something} />
//inside MyComponent:
...
<button onClick={input => setSomeValueFromContext(input)}>...
...
Run Code Online (Sandbox Code Playgroud)
MyComponent仅当上下文中的特定道具使用新值更新时才会重新渲染,否则它将保留在那里。select每次更新上下文中的任何值时,里面的代码都会运行,但它什么也不做,而且很便宜。
我建议查看使用 React.memo 和 useContext 钩子防止重新渲染。
据我了解,context API 并不是为了避免重新渲染,而是更像 Redux。如果您希望避免重新渲染,也许可以查看PureComponent生命周期钩子shouldComponentUpdate。
这是一个提高性能的重要链接,您也可以将其应用于上下文 API
| 归档时间: |
|
| 查看次数: |
2209 次 |
| 最近记录: |