# 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之類的)