我有一个简单的react应用,其中有一个 FruitsList 组件用于显示列表中的水果,一个 FruitForm 组件用于添加水果,并且都包含在水果组件中。我正在使用useContext
和useReducer
来管理水果的状态。我已经为它创建了一个 FruitContext 。我想停止 FruitForm 的重新渲染,因为它仅使用分派功能,并且每次添加新水果时都无法重新渲染它。请提出任何解决方案。
表单组件
const Form = () => {
const { dispatch } = useContext(FruitsContext);
const { setLoading } = useContext(LoaderContext);
let formRef = null;
const fruit = {};
const formSubmitHandler = async (event) => {
event.preventDefault();
setLoading(true);
await fetch('https://fruit-basket-74269.firebaseio.com/fruits.json', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(fruit)
});
dispatch({type: 'ADD', fruit: fruit});
// formRef.reset();
setLoading(false);
}
return (
<Card>
{console.log('[Form]')}
<form ref={ref => formRef = ref} onSubmit={formSubmitHandler} className={style.form} autoComplete="off">
<div className={style.formGroup}>
<input onChange={event => fruit.item = event.target.value} className={style.input} type="text" id="name" placeholder="Enter fruit name" />
<label className={style.label} htmlFor="name">Name</label>
</div>
<div className={style.formGroup}>
<input onChange={event => fruit.qty = event.target.value} className={style.input} type="number" min="0" id="qty" placeholder="Enter quantity" />
<label className={style.label} htmlFor="qty">Quantity</label>
</div>
<Button>Add Fruit</Button>
</form>
</Card>
)
}
export default React.memo(Form);
水果列表
const FruitList = () => {
const { fruits } = useContext(FruitsContext);
console.log('[FruitList]:', fruits);
return useMemo(() => {
return (
<div className={style.fruitList}>
<h2 className={style.heading}>Fruits</h2>
<hr />
<div className={style.list}>
<FruitCard name={'Apple'} qty={15} />
<FruitCard name={'Orange'} qty={10} />
<FruitCard name={'Grapes'} qty={20} />
</div>
</div>
);
}, []);
}
export default FruitList;
水果
const Fruits = () => {
console.log('[Fruits Parent]');
// const { loading } = useContext(LoaderContext);
return (
<div className={style.fruits}>
{/* {loading && <Loader />} */}
<Form />
<br />
<Filter />
<br />
<FruitList />
</div>
)
}
export default Fruits
FruitContext
export const FruitsContext = createContext();
const FruitsProvider = ({children}) => {
const [fruits, dispatch] = useReducer(reducer, []);
const value = ({
fruits, dispatch
});
return (
<FruitsContext.Provider value={value}>
{ children }
</FruitsContext.Provider>
);
}
export default FruitsProvider;
FruitReducer
export default (state, action) => {
switch(action.type) {
case 'LOAD':
return action.fruits
case 'ADD':
console.log('[Pre-Action]', state);
const newList = [...state];
newList.push(action.fruit);
console.log('[Post-Action]', newList);
return newList;
case 'DELETE':
return state.filter(fruit => fruit.id !== action.id);
default: return state;
}
}
答案 0 :(得分:0)
如果提供者值中的任何值发生更改,则消耗上下文的组件将始终重新呈现。不管您是否实际使用该值(例如,在这种情况下,即使您仅拉出调度功能)。
通常,对于大多数React应用程序,您不需要优化类似的内容,React已经非常快,并且不会损害其他一些渲染器。任何性能问题都可以在何时何地解决。 如果要从一开始就进行优化,则可以将reducers状态拆分并分配到两个不同的上下文中。它们都可以放在同一个ProviderComponent中,但是必须有两个不同的Context.Provider组件。一个将状态用作值,另一个将调度功能用作值。 如果您随后使用了调度上下文,那么如果调度操作更改了状态,则不会导致组件重新呈现。
//更新
例如:
const FruitsProvider = ({children}) => {
const [fruits, dispatch] = useReducer(reducer, []);
return (
<FruitsStateContext.Provider value={fruits}>
<FruitsDispatchContext.Provider value={dispatch}>
{ children }
</FruitsDispatchContext.Provider>
</FruitsStateContext.Provider>
);
}
我还建议不要直接导出上下文,而是导出暴露状态或调度信息的钩子。
例如
export const useFruits = () => {
const fruitsState = React.useContext(FruitsStateContext);
if (!fruitsState) {
throw new Error('you cant use the useFruits hook outside the FruitsStateContext');
}
return fruitsState;
}