背景
年底了,换了项目组,新的项目组应用react,从vue到react,我只花了一天的工夫,看了官网简略的文章之后,就感觉这玩意很简略啊,比起vue的那么api来说,这基本没有学习老本好吧,十分迅速的就进入了react的我的项目开发,并且怏怏不乐,依据我多年的教训来看,这波必定会失去领导的赏识
很快,我就做完了我的需要,把代码提交下来,组长可能的确比拟闲,还review了我的代码,并且指出了一系列的问题,并通知我说学习react最难的局部,并不是晓得怎么应用它,而是要晓得怎么可能编写良好,洁净的react代码
次要给我提了六点谬误,我置信在座的各位,可能须要对号入座
在不须要应用state的时候应用state
波及到我的项目中的代码逻辑,咱们将一些内容通过demo的模式展现进去
提交表单在很多场景下都须要用到,对于一些表单的提交,大多数人的代码的实现可能是以下形式
export default function App() { const [name, setName] = useState(""); const submit = (e) => { e.preventDefault(); console.log(name); }; const change = (e) => { setName(e.target.value); }; return ( <div className="container"> <form onSubmit={submit}> <label htmlFor="name">姓名: </label> <input value={name} onChange={change} type="text" id="name" /> </form> </div> );}
页面上有一个姓名输入框,通过state的形式将数据绑定,提交的时候从state上再把数据取到,这一点的确很像vue的双向绑定,通过state的形式实现了,看着外表没有问题,并且页面也出现了,submit的数据也取到了
然而实际上,咱们并没有在别的中央应用这个name状态,除了在提交的时候,有人会说,value也用到了,然而实际上你是能够不须要value这个字段的,只有提交的时候才会用到这个数据,所以这里齐全能够不应用state,避免组件刷新
只须要通过ref改一下即可
export default function App() { const nameRef = useRef(null); const submit = (e) => { e.preventDefault(); console.log(nameRef.current.value); }; return ( <div className="container"> <form> <label htmlFor="name">姓名: </label> <input ref={nameRef} type="text" id="name" /> </form> <button onClick={submit}>提交</button> </div> );}
和之前一样,咱们点提交按钮的时候获取到了最新数据,并且页面没有屡次刷新
useState的回调函数
那什么状况下应用useState呢?这种在页面上出现的内容须要应用,比方一个计数器
export default function App() { const [count, setCount] = useState(0); const submit = (val) => { setCount(count + val); }; return ( <div className="container"> <button onClick={() => submit(-1)}>-1</button> <span>{count}</span> <button onClick={() => submit(1)}>+1</button> </div> );}
外表看着没有问题,点击加减也都挺失常的,然而如果你是相熟useState的话,你也会给setCount传递一个函数的模式,这两者表现形式仿佛齐全一样,感触不到区别
const submit = (val) => { setCount((current) => current + val);};
那具体的区别在哪呢?在不应用回调函数的时候,如果咱们间断更新状态的话,像上面这样
setCount(count + val)setCount(count + val)
实际上页面也只会加一次,因为在这一次的更新过程中,count的值是固定的,也就是咱们常说的setState是异步的起因(当你更改状态的时候,它不会立即更新,而是等到下一次render才会更新),并且react会将state进行批处理,然而如果是函数的模式
const submit = (val) => { setCount((current) => current + val); setCount((current) => current + val);};
就可能失去想要的后果,所以如果你想应用之前的状态来进行state值的批改,最好应用函数模式
state异步更新,useEffect的应用
通过上一个count,咱们晓得咱们立即获取count值的时候获取到的不是最新值
const submit = (val) => { setCount((current) => current + val); console.log(count); };
这时候有人就想到了useEffect,如此就获取到了新的值
useEffect(() => { console.log(count)}, [count])
而后对于这一点,很多同学就将useEffect当成了vue中的watch,实现了上面的逻辑
export default function App() { const [user, setUser] = useState(""); const [name, setName] = useState(""); const [userName, setUserName] = useState(""); useEffect(() => { setUserName(user + name); }, [user, name]); return ( <div className="container"> <input type="text" value={user} onChange={(e) => setUser(e.target.value)} /> <input type="text" value={name} onChange={(e) => setName(e.target.value)} /> <span>{userName}</span> </div> );}
咋一看如同没什么问题,并且实现了对应的性能,然而它不是最佳形式
理论齐全能够不必userName这个state,间接在dom中<span>{user + name}</span>
就能实现对应的成果
有时候很多同学也会应用useEffect进行上面的操作
useEffect(() => { fetch('#').then(d => setData(d))}, [])useEffect(() => { console.log(d)}, [d])
那为什么你不把console.log的逻辑放在.then外面呢?
常见useEffect谬误
const [user, setUser] = useState("");const person = { user}useEffect(() => { console.log(person)}, [person])
这种状况,大多数会认为useEffect会在组件初始化的时候执行一次,但实际上useEffect中的回调会执行屡次,因为person是个援用类型,每次的指针地址都是变动的
这个时候你能够应用useMemo来解决这个问题
const person = useMemo(() => ({ user}), [user])
依赖问题
因为业务很简单,所以在一直迭代的过程中,咱们的effect通常就会变成这种状况
useEffect(() => { ......}, [person, name, age, id, status, address ....])
依赖会越来越多,略微改其中的一个点,就会执行effect大片的逻辑,这里最好可能拆分或者合并,确定要执行一个逻辑的,最好放在一个state中,比方能够将age,name,id,等根底信息放在一个state,而后这个effect依赖这一个state就能够了,进行state合并
总结
上述就是一些根底react使用者常呈现的一些问题,hook的确能给咱们带来很大的便当,然而有时候从vue到react,其中的一些思维还是须要做一些调整,能力更好的适应hooks的形式,咱们能够多看看好的一些hooks的封装,加深一些hooks的了解,也欢送大家关注公众号【FE情报局】,一起探讨一些技术文章