Should I use useselector instead of mapStateToProps

别说谁变了你拦得住时间么 提交于 2020-12-04 19:53:55

问题


When creating a React app, if I use the hook useSelector, I need to adhere to the hooks invoking rules (Only call it from the top level of a functional component). If I use the mapStateToProps, I get the state in the props and I can use it anywhere without any issues...

What are the benefits of using the hook besides saving lines of code compared to mapStateToProps?


回答1:


Since no one knows how to answer, it seems like the best answer is that you should NOT be using useselector when you need information in other places other than the root level of your component. Since you don't know if the component will change in the future, just don't use useselector at all.

If someone has a better answer than this, I'll change the accepted answer.

Edit: Some answers were added, but they just emphasize why you shouldn't be using useselector at all, until the day when the rules of hooks will change, and you'll be able to use it in a callback as well.




回答2:


I think you misunderstand what "top level" is. It merely means that, inside a functional component, useSelector() cannot be placed inside loops, conditions and nested functions. It doesn't have anything to do with root component or components structure

// bad
const MyComponent = () => {
  if (condition) {
    // can't do this
    const data = useSelector(mySelector);
    console.log(data);
  }

  return null;
}

---

// good
const MyComponent = () => {
  const data = useSelector(mySelector);

  if (condition) {
    console.log(data); // using data in condition
  }

  return null;
}

If anything, mapStateToPtops is located at even higher level than a hook call

the rules of hooks make it very hard to use that specific hook. You still need to somehow access a changing value from the state inside callbacks

To be fair you almost never have to access changing value inside a callback. I can't remember last time I needed that. Usually if your callback needs the latest state, you are better off just dispatching an action and then handler for that action (redux-thunk, redux-saga, redux-observable etc) will itself access the latest state

This is just specifics of hooks in general (not just useSelector) and there are tons of ways to go around it if you really want to, for example

const MyComponent = () => {
  const data = useSelector(mySelector);
  const latestData = useRef()
  latestData.current = data

  return (
    <button
      onClick={() => {
        setTimeout(() => {
          console.log(latestData.current) // always refers to latest data
        }, 5000)
      }}
    />
  )
}

What are the benefits of using the hook besides saving lines of code compared to mapStateToProps?

  1. You save time by not writing connect function any time you need to access store, and removing it when you no longer need to access store. No endless wrappers in react devtools
  2. You have clear distinction and no conflicts between props coming from connect, props coming from parent and props injected by wrappers from 3rd party libraries
  3. Sometimes you (or fellow developers you work with) would choose unclear names for props in mapStateToProps and you will have to scroll all the way to mapStateToProps in the file to find out which selector is used for this specific prop. This is not the case with hooks where selectors and variables with data they return are coupled on the same line
  4. By using hooks you get general advantages of hooks, the biggest of which is being able couple together and reuse related stateful logic in multiple components
  5. With mapStateToProps you usually have to deal with mapDispatchToProps which is even more cumbersome and easier to get lost in, especially reading someone else's code (object form? function form? bindActionCreators?). Prop coming from mapDispatchToProps can have same name as it's action creator but different signature because it was overridden in mapDispatchToprops. If you use one action creator in a number of components and then rename that action creator, these components will keep using old name coming from props. Object form easily breaks if you have a dependency cycle and also you have to deal with shadowing variable names

.

import { getUsers } from 'actions/user'

class MyComponent extends Component {
  render() {
    // shadowed variable getUsers, now you either rename it
    // or call it like this.props.getUsers
    // or change import to asterisk, and neither option is good
    const { getUsers } = this.props
    // ...
  }
}

const mapDispatchToProps = {
  getUsers,
}

export default connect(null, mapDispatchToProps)(MyComponent)



回答3:


The redux state returned from the useSelector hook can be passed around anywhere else just like its done for mapStateToProps. Example: It can be passed to another function too. Only constraint being that the hook rules has to be followed during its declaration:

  1. It has to be declared only within a functional component.

  2. During declaration, it can not be inside any conditional block . Sample code below

        function test(displayText) {
           return (<div>{displayText}</div>);
        }
    
        export function App(props) {
            const displayReady = useSelector(state => {
            return state.readyFlag;
            });
    
            const displayText = useSelector(state => {
            return state.displayText;
            });
    
            if(displayReady) {
                return 
                (<div>
                    Outer
                    {test(displayText)}
    
                </div>);
            }
            else {
            return null;
            }
        }
    

EDIT: Since OP has asked a specific question - which is about using it within a callback, I would like to add a specific code.In summary, I do not see anything that stops us from using useSelector hook output in a callback. Please see the sample code below, its a snippet from my own code that demonstrates this particular use case.

export default function CustomPaginationActionsTable(props) {
//Read state with useSelector.
const searchCriteria = useSelector(state => {
  return state && state.selectedFacets;
 });

//use the read state in a callback invoked from useEffect hook.
useEffect( ()=>{
  const postParams = constructParticipantListQueryParams(searchCriteria);
  const options = {
    headers: {
        'Content-Type': 'application/json'
    },
    validateStatus: () => true
  };
  var request = axios.post(PORTAL_SEARCH_LIST_ALL_PARTICIPANTS_URI, postParams, options)
      .then(function(response)
        { 
          if(response.status === HTTP_STATUS_CODE_SUCCESS) {
            console.log('Accessing useSelector hook output in axios callback. Printing it '+JSON.stringify(searchCriteria));
            
          }
                    
        })          
      .catch(function(error) {
      });
}, []);
}


来源:https://stackoverflow.com/questions/59748180/should-i-use-useselector-instead-of-mapstatetoprops

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!