接觸react-hook已經(jīng)很久了,用了之后,發(fā)現(xiàn)真的很強(qiáng)大,記錄一下最近使用的想法
useState
首先接觸到的就是useState
state只是一個(gè)狀態(tài),但是之前class就需要寫的很大,相比之下,寫成hook就簡化了很多
class Age extends React.Component {
constructor(props) {
super(props);
this.state = {
age: 20
};
}
handleOnChange = e => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
render() {
return (
<>
<div>age: {this.state.age}</div>
<input name="age" onChange={handleOnChange} />
</>
);
}
}
用了hook之后,就變得很簡潔了
const Age = () => {
const [age, setAge] = React.useState(20);
const handleOnChange = e => {
const { value } = e.target;
setAge(value);
};
return (
<>
<div>age: {age}</div>
<input name="age" onChange={handleOnChange} />
</>
);
};
useEffect
對于useEffect我最初以為是用來替代生命周期,比如componentDidMount,但是事實(shí)證明他真的很強(qiáng)大,[name]括號里面的是依賴,依賴一變,就會(huì)重新執(zhí)行,多個(gè)依賴就更棒了,如果是用之前的寫法,就要在 componentWillReceiveProps里面寫很多if來比較nextProps和this.props
而且這個(gè)最強(qiáng)大就是可以抽出來,當(dāng)一個(gè)反復(fù)利用reuseable的hook
傳入不同的localStorageKey,就可以存不同的數(shù)據(jù)到localStorage, 這樣就方便重復(fù)實(shí)用了,而且每次value變了,就會(huì)自動(dòng)保存到localStorage
const useLocalStorage = localStorageKey => {
const [value, setValue] = React.useState(
localStorage && localStorage.getItem(localStorageKey)
);
React.useEffect(() => {
localStorage && localStorage.setItem(localStorageKey, value);
}, [value, localStorageKey]);
return [value, setValue];
};
useRef
有些時(shí)候,會(huì)發(fā)現(xiàn),其實(shí)數(shù)據(jù)并沒有變化,但是還是觸發(fā)了setState或者是別的callback,這樣會(huì)導(dǎo)致,調(diào)用的函數(shù)太多,從而影響了性能,所以比較兩個(gè)對象是不是相等,只有當(dāng)不等,才更新,這樣可以減小一點(diǎn)re-render。
這時(shí)候,就是useRef登場的時(shí)候了,搭配實(shí)用lodash.isEqual, 可以比較大的object
const usePrevious = value => {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
};
#使用
const myPreviousState = usePrevious(conditions);
useEffect(() => {
if (myPreviousState && !_.isEqual(myPreviousState, conditions)) {
onChange(conditions);
}
}, [myPreviousState, conditions, onChange ])
useContext
context呢,我之前一直覺得這個(gè)東西很高大上,很復(fù)雜,一直不敢用,但是后來發(fā)現(xiàn),他就是對應(yīng)上下文,比如傳遞props,一般都是使用parent傳給child,但是如果,A -> B -> C -> D,但其實(shí)B和C都沒用到,只有D用到了,那么D要來修改A,就需要再往上傳遞,導(dǎo)致B和C一直在反反復(fù)復(fù)被重新渲染,這時(shí)候,當(dāng)當(dāng)當(dāng)當(dāng),context就可以發(fā)揮很大的作用,在A里面包一下Provider,然后到D直接用createContext和useContext拿出來就可以用了,這樣代碼也不會(huì)忘了忘記中間的B,C的pass props,看起來也清楚,何樂而不為呢
const NameContext = createContext();
const A = () => (
<NameContext.Provider value={{ username, setUserName }}>
<B />
</NameContext.Provider>
);
const Names = () => {
const { username, setUserName } = useContext(NameContext);
const { names, onChange } = useNames({ username, setUserName });
return (
<div>
<label>firstName</label>
<input
name="firstName"
value={names && names.firstName}
onChange={onChange}
/>
<label>lastName</label>
<input
name="lastName"
value={names && names.lastName}
onChange={onChange}
/>
</div>
);
};
useReducer
最后是用到redux, 之前對于redux的理解一直如果當(dāng)一個(gè)對象,要被很多不同的地方共享和修改,那么放到redux是最合適不過。但是知道我遇到了,一個(gè)嵌套很深的一個(gè)object,要更新里面的某一個(gè)字段真的要寫好多好多層,然后我翻到了hook對于useReducer的介紹
Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values.
useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks
現(xiàn)在的reducer是相對于useState而言的,他更加適合復(fù)雜的,有很多sub-values的對象的更新
import React, { useEffect, useContext, createContext, useReducer } from "react";
const NameContext = createContext();
const init = initial => {
return { name: initial };
};
const reducer = (state, action) => {
switch (action.type) {
case "firstName":
return {
...state,
name: {
firstName: action.payload
}
};
case "lastName":
return {
...state,
name: {
lastName: action.payload
}
};
default:
return state;
}
};
const useNames = ({ username, setUserName }) => {
// const [names, setNames] = React.useState(username);
const [state, dispatch] = useReducer(reducer, username, init);
const names = state.name;
const onChange = e => {
const { name, value } = e.target;
dispatch({ type: name, payload: value });
};
useEffect(() => {
setUserName(names);
}, [names, setUserName]);
return {
names,
onChange
};
};
const Names = () => {
const { username, setUserName } = useContext(NameContext);
const { names, onChange } = useNames({ username, setUserName });
return (
<div>
<label>firstName</label>
<input
name="firstName"
value={names && names.firstName}
onChange={onChange}
/>
<label>lastName</label>
<input
name="lastName"
value={names && names.lastName}
onChange={onChange}
/>
</div>
);
};
const App = () => {
const [username, setUserName] = React.useState({
firstName: "Rachel",
lastName: "Green"
});
return (
<NameContext.Provider value={{ username, setUserName }}>
<Names />
</NameContext.Provider>
);
};
export default App;
完成了一個(gè)簡簡單單的name 表單組
