---
# System prepended metadata

title: react

---

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