vue和react中props變化后如何修改state
vue和react中props變化后修改state
如果只想在 state 更改時(shí)重新計(jì)算某些數(shù)據(jù),比如搜索框案例。
vue
<template> <div> <input type="text" v-model="filterText"> <ul> <li v-for="item in filteredList" :key="item.id"> {{ item.text }} </li> </ul> </div> </template>
<script> export default { props: { list: { type: Array, default: () => ([]) } }, data () { return { filterText: '' } }, computed: { filteredList () { return this.list.filter(item => item.text.includes(this.filterText)) } } } </script>
react
import React, { PureComponent } from 'react'; class Example extends PureComponent { state = { filterText: '' }; handleChange = event => { this.setState({ filterText: event.target.value }) } render() { const filteredList = this.filter(this.props.list, this.state.filterText) return ( <> <input type="text" onChange={this.handleChange} value={this.state.filterText} /> <ul> { filteredList.map( item => <li key={item.id}>{item.text}</li> ) } </ul> </> ); } }
如果你想在 prop 更改時(shí)“重置”某些 state,比如隨機(jī)默認(rèn)值案例
vue
Vue提供了一種更通用的方式來(lái)觀察和響應(yīng)Vue實(shí)例上的數(shù)據(jù)變動(dòng):偵聽(tīng)屬性 watch。
<template> <div> <input type="text" v-model="text"> </div> </template>
<script> export default { props: { email: { type: String, default: '' } }, data () { return { text: '' } }, watch: { email: { immediate: true, handler (value) { this.text = value } } } } </script>
react
React生命周期 getDerivedStateFromProps 會(huì)在調(diào)用 render 方法之前調(diào)用,并且在初始掛載及后續(xù)更新時(shí)都會(huì)被調(diào)用。它應(yīng)返回一個(gè)對(duì)象來(lái)更新 state,如果返回 null 則不更新任何內(nèi)容。
父組件重新渲染時(shí)觸發(fā),請(qǐng)注意,不管原因是什么,都會(huì)在每次渲染前觸發(fā)此方法。
class Example extends Component { state = { text: '' }; handleChange = (event) => { this.setState({ text: event.target.value }) } static getDerivedStateFromProps(nextProps, prevState) { if (prevState.email !== nextProps.email) { return { text: nextProps.email, email: nextProps.email } } return {text: prevState.text} } render() { return ( <> <input type="text" onChange={this.handleChange} value={this.state.text} /> </> ); } }
改進(jìn)
直接復(fù)制 prop 到 state 是一個(gè)非常糟糕的想法。這兩者的關(guān)鍵在于,任何數(shù)據(jù),都要保證只有一個(gè)數(shù)據(jù)來(lái)源,而且避免直接復(fù)制它。
vue
<template> <div> <input type="text" :value="value" @input="handleInput"> </div> </template>
<script> export default { props: { value: { type: String, default: '' } }, methods: { handleInput (e) { this.$emit('input', e.target.value) } } } </script>
<template> <div id="app"> <Example v-model="email"/> <button @click="handleClick">默認(rèn)值</button> </div> </template>
<script> import Example from './components/Example.vue' export default { components: { Example }, data () { return { email: '' } }, methods: { handleClick () { this.email = String(Math.random()) } } } </script>
react
function Example (props) { return <input onChange={props.onChange} value={props.email} />; }
class App extends React.Component { state = { email: '' } handleClick = () => { this.setState({ email: String(Math.random()) }) } handleChange = (event) => { this.setState({ email: event.target.value }) } render() { return ( <> <Example email={this.state.email} onChange={this.handleChange} /> <div> <button onClick={this.handleClick}>默認(rèn)值</button> </div> </> ); } }
react改變state必須知道的知識(shí)點(diǎn)
react可以通過(guò)this.state.xx的方式直接獲取state,但是當(dāng)我們修改state的時(shí)候,往往有許多的坑。
1.不能直接修改state
組件修改state,并不會(huì)重新觸發(fā)render。例如:
?//錯(cuò)誤 this.state.title='attend'; //正確 this.setState({title:'attend'});
2.state的更新是異步的
調(diào)用setState時(shí),組件state并不會(huì)立即改變,只是把要修改的狀態(tài)放入事件隊(duì)列當(dāng)中,為了彌補(bǔ)這個(gè)問(wèn)題,使用另一種 setState() 的形式,接受一個(gè)函數(shù)。
這個(gè)函數(shù)將接收前一個(gè)狀態(tài)作為第一個(gè)參數(shù),應(yīng)用更新時(shí)的 props 作為第二個(gè)參數(shù),代碼如下:
//正確 this.setState((prevState, props)=>({ ?? ?counter: prevState.counter + 1 }))
3.state的更新是一個(gè)合并的過(guò)程
當(dāng)調(diào)用setState()修改組件的狀態(tài)時(shí),只需要傳入發(fā)生改變的state,而不是完整的state,因?yàn)榻M件state的更新是一個(gè)合并的過(guò)程:
this.state = { ?? ?title: 'React', ?? ?content: 'React is an wondeful JS library' }
當(dāng)只需要修改title時(shí),只需要將修改的title傳給setState即可:
this.setState({title:'ReactJs'});
react會(huì)合并最新的title到原來(lái)的狀態(tài),同時(shí)保留原來(lái)狀態(tài)的content,最終合并state為:
this.state = { ?? ?title: 'ReactJs', ?? ?content: 'React is an wondeful Js library' }
state與不可變對(duì)象
react官方把state當(dāng)成不可變對(duì)象,一方面直接修改this.state,組件并不會(huì)重新render;另一方面,state中包含的所有狀態(tài)都應(yīng)該是不可變的對(duì)象,state當(dāng)中的某一個(gè)狀態(tài)發(fā)生變化時(shí),應(yīng)該重新創(chuàng)建這個(gè)狀態(tài)對(duì)象,而不是直接修改原來(lái)的state狀態(tài),那么當(dāng)狀態(tài)發(fā)生變化時(shí),如何去創(chuàng)建新的狀態(tài)呢,我們根據(jù)狀態(tài)類型可以分為下面三種情況:
狀態(tài)類型為不可變類型
number、string、boolean、null、undefined
這種情況最簡(jiǎn)單,因?yàn)闋顟B(tài)是不可變類型,所以直接給要修改的狀態(tài)賦一個(gè)新值即可,例如我們要修改的count為number型,title(string),success(boolean)三個(gè)狀態(tài):
this.setState({ ?? ?count:1, ?? ?title:'React', ?? ?success:true })
狀態(tài)類型為數(shù)組
假如有一個(gè)數(shù)組類型的狀態(tài)books,當(dāng)向books中增加一本書(shū)時(shí)。
//方法一:使用preState,concat創(chuàng)建新數(shù)組 ?this.setState((prevState)=>({ ?? ?books: prevState.books.concat(['React Guide']) })) //方法二:ES6 spread syntax this.setState(prevState=>({ ?? ?books:[...prevState,'React Guide'] }))
當(dāng)我們從books中截取部分元素作為新?tīng)顟B(tài)時(shí),可以用數(shù)組的slice方法:
this.setState(prevState=>({ ?? ?books: prevState.books.slice(1,3); }))
當(dāng)從books中過(guò)濾部分元素后,作為新?tīng)顟B(tài)時(shí),可以使用filter方法:
this.setState(prevState=>({ ?? ?books: prevState.books.filter(item=>{ ?? ? ?return item!='React'; ?? ?}) }))
【注意】不要使用push,pop,shift,unshift,splice等方法修改數(shù)組類型的狀態(tài),因?yàn)檫@些方法都是在原數(shù)組的基礎(chǔ)上修改的,而concat,slice,filter會(huì)返回一個(gè)新的數(shù)組。
狀態(tài)的類型是普通對(duì)象
(1) 使用es6的Object.assgin()方法
this.setState({ ?? ?onwer: Object.assgin({},preState.onwer,{name:'Jason'}); })
(2) 使用對(duì)象擴(kuò)展語(yǔ)法(Object spread properties):
this.setState(preState=>{ ?? ?owner: {...preState.owner, name:'Jason'} })
總結(jié)
創(chuàng)建新的狀態(tài)的關(guān)鍵是避免使用直接修改原對(duì)象的方法,這種方法在vue中稱為變異方法,而是使用可以返回一個(gè)新對(duì)象的方法,當(dāng)然可以使用Immutable的JS庫(kù)(Immutable.js)實(shí)現(xiàn)類似的效果。
思考
為什么React推薦組件狀態(tài)的修改是不可變對(duì)象呢?
(1) 不可變對(duì)象的修改會(huì)返回一個(gè)新的對(duì)象,不用擔(dān)心原對(duì)象在不小心的情況下修改導(dǎo)致的錯(cuò)誤,方便程序的管理和調(diào)試。
(2) 處于性能的考慮,對(duì)象組件的狀態(tài)是不可變對(duì)象時(shí),在組件的shouldComponentUpdate方法中僅需要比較前后兩次狀態(tài)對(duì)象的引用就可以判斷狀態(tài)是否真的改變,從而避免不必要的render調(diào)用。
進(jìn)階
除了以上方法改變r(jià)eact組件的狀態(tài)之外,我們還經(jīng)常會(huì)用到replaceState()改變組件的狀態(tài)。
replaceState()方法與setState()類似,但是方法只會(huì)保留nextState中狀態(tài),原state不在nextState中的狀態(tài)都會(huì)被刪除。
//使用語(yǔ)法: replaceState(object nextState[, function callback])
nextState
,將要設(shè)置的新?tīng)顟B(tài),該狀態(tài)會(huì)替換當(dāng)前的state。callback
,可選參數(shù),回調(diào)函數(shù)。該函數(shù)會(huì)在replaceState設(shè)置成功,且組件重新渲染后調(diào)用。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue動(dòng)態(tài)路由匹配和路由懶加載多種方法詳解
這篇文章主要介紹了vue動(dòng)態(tài)路由匹配和路由懶加載,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06Ant?Design?Vue?修改表格頭部樣式的詳細(xì)代碼
這篇文章主要介紹了Ant?Design?Vue?修改表格頭部樣式,首先用到的是customHeaderRow這個(gè)API,類型是一個(gè)函數(shù),本文通過(guò)完整代碼給大家詳細(xì)講解,需要的朋友可以參考下2022-10-10使用element-ui實(shí)現(xiàn)行合并過(guò)程
這篇文章主要介紹了使用element-ui實(shí)現(xiàn)行合并過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08Vue Router去掉url中默認(rèn)的錨點(diǎn)#
vue-router默認(rèn)hash模式——使用URL的hash來(lái)模擬一個(gè)完整的URL,于是當(dāng)URL改變時(shí),頁(yè)面不會(huì)重新加載。這篇文章主要介紹了Vue Router去掉url中默認(rèn)的錨點(diǎn)#,需要的朋友可以參考下2018-08-08vue實(shí)現(xiàn)pdf文檔在線預(yù)覽功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)pdf文檔在線預(yù)覽功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11