# react - react render 接受react element(可以來自react component(jsx其實也是被編譯成react element)),並render他。 - 每次更新element(在component中setState被觸發的時候)時,會去比較與上個element的差異,並更新畫面。 <!-- :::info - react element是一個結構像這樣的東西 ``` const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } }; ``` ::: --> ## component ### 形式 - function: 可以 return 一個 react element 的function - class: extends React.Component(必須有render)的class - lifecycle - 可以用來在component自動做某些事之前/後做事情(ex: 在construct時去bind東西)https://zh-hant.reactjs.org/docs/react-component.html - Mounting //component被創造 - constructor() - static getDerivedStateFromProps() - render() - componentDidMount() - update // setState之後 - static getDerivedStateFromProps() - shouldComponentUpdate() - render() - getSnapshotBeforeUpdate() - componentDidUpdate() - Unmounting //element被弄掉的時候 - componentWillUnmount() ### 擁有 #### props - 用來顯示或傳下去 - 從parent傳下來的東西 - 不可以改它 - this.props.children - 他會是jsx裡給的children - 不太確定實際上會用來做什麼,不過我猜是在用別人的code時會用到 - Validate傳入的props - propType - https://zh-hant.reactjs.org/docs/typechecking-with-proptypes.html #### state - component用來更新render的element - 每個component自己的東西 - setState - 會觸發重新render(不要直接改state) - setState是非同步的,在他之後不要再用this.state(會拿到還沒改過的值) - setState(updater, callback) - 這裡如果用updater((state, props) => {})會幫你傳進最新的 - setState(object) :::info - 跟別的component合作(不只是傳下去顯示的情況) - 在第一個共同的ancestor裡加一個state(以及能修改state的function),把他們傳下去 ::: #### ref - 用來讓ancestor可以access某一個element - React.createRef後把他給一個child,(child用React.forwardRef拿到之後可以再給下一個child。)最後被附上ref的,可以在一開始的ancestor的ref.current拿到 #### key - react用來比對的東西 - component內不能拿到 - 在有一樣的siblings時,react會要求你給他 ## JSX - 用來更容易的create react element - 不能第一層就有siblings,一定要的話可以用React.Fragment https://zh-hant.reactjs.org/docs/fragments.html - {}裡面放js ### event - 在jsx中可以給予element Event Handlers - https://reactjs.org/docs/events.html - 關於bind / this - 使用function () {} 時,請自己this.{...}.bind - 使用arrow function的時候可以直接拿到這個component的this :::info - js 的this 對於()=> {} 和 function () {}是不一樣的 - () => {} 是從他的context得到 - function () {} 是從擁有他的object得到 ::: # redux 把一群state放在一起(store中),並只能透過[store](#store)去改變它(dispatch一個[action](#action),讓store用自己的[reducer](#reducer)去改變自己的狀態),讓本來分散在各處的state和改變state的方式能集中在一起。 ## store ### store可以做的事 - getState() - 拿到現在的state - dispatch(action) - 把收到的action和現在的state給reducer,讓reducer去改變自己的狀態 - subscribe(listener) - 在state改變以後做一些事,會回傳一個用來撤銷 listener 的 function。(在react-redux中有寫好的connect) ### 創造store - createStore(reducer, [preloadedState], [enhancer]) - [reducer](#reducer) - 利用現在的state和發生的[action](#action)更新自己state的方式 - preloadedState - enhancer - 一些其他的擴充的東西(ex: [middleware](#middleware) 或 debug工具) ## action - 告訴store現在要發生什麼事的object - 一定要有type,然後可以加上需要的一些data - [bindActionCreators](https://redux.js.org/api/bindactioncreators) - 讓child可以dispatch一些action,但是不想給他整個dispatch的時候。(讓child只能dispatch部分action & 在child裡可以直接call function,不用自己去import或理解這個action) (不過要是這個child是react裡一個有connect的component 可以用mapDispatchToProps給) ## reducer - 拿到action並去改變state的function `reducer(previousState, action) => newState` - 最好要是pure function - combineReducers( reducers_obj ) - 把多個reduce function 變成一個可以傳給createStore的reducer。 - ```javascript= combineReducers({ state_ele1: state_ele1 => new_state_ele1; // gen_state_ele1_reducer state_ele2: state_ele2 => new_state_ele2; // gen_state_ele2_reducer }); ``` ## middleware - 在reducer拿到action之前,對這個action做一些事。(用api之類的) - `dispatch_caller` -dispatch-> `middleware1` -next-> `middleware2` -next-> `reducer` -return-> `middleware2` -return-> `middleware1` -return-> `dispatch_caller` - `const middleware = store => next => action => { return next(action);} ` - store - 被dispatch的store - next - 呼叫下一個middleware的方式 - action - dispatch時給的action或是上一個middleware交過來的action - 使用middleware - 在createStore的時候傳給store `applyMiddleware(...middlewares)` (有其他enhancer的時候可以用 [compose](https://chentsulin.github.io/redux/docs/api/compose.html) 組在一起) - ```javascript= const store = createStore( reducer, preloadedState, applyMiddleware(...middleware) ) ``` # react-redux - 把東西放在Provider裡面,並把store傳給Provider,就能讓這裡面的element都可以去subscribe這個store。 - 實際讓component subscribe redux的state: - 利用connect形成一個新的component - 新的component在有action被dispatch時,就會去把新的state map成這個新的component需要的prop並更新他。 ## connect ```javascript= function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)(react_component) ``` ### `mapStateToProps (state, ownProps?)` - 讓compnent從store state拿到props可以顯示 - 拿到整份新的state的狀態,決定如何給與這個component的props並回傳props obj ### `mapDispatchToProps (dispatch, ownProps?)` 或可以是一個object - 讓component可以更新state - 拿這個store的dispatch,用來讓這個component可以做一些改變state的事。 ### `mergeProps (stateProps, dispatchProps, ownProps)` - mapStateToProps和mapDispatchToProps後得到的props有機會合作。(根據新的state決定最後的dispatch function之類的)