n179911a
n179911a

Reputation: 155

How can I expose React Hook outside of my React Functional Component

I have a React Functional Component like this:

export const MyParentComponent = (props: Props) => {
    const [myObjects, setMyObjects = React.useState< MyClass[] | undefined>(undefined);

  //...
}

I have an array of 'MyClass' objects, in myObjects and put that in the 'State' of React since that will affect MyParentComponent rendering.

My question is how can I expose setMyObjects method to class outside of MyParentComponent so that the caller can set a new array of MyObjects and trigger a rendering of MyParentComponent ?

Upvotes: 0

Views: 1591

Answers (2)

DevThiman
DevThiman

Reputation: 1138

since you want to change the state of MyParentComponent in outside of that component, that outside component need to be a child, since you can need to pass the setMyObjects function as a prop. In other way you can you react feature called Context API to access the state of a component which is not Descendant. React Context API

This is a simple scenario that elaborates how to change the state of the parent component inside the child component by passing setState function as a prop to child.

const Movie = () => { // This is the Parent component which render movies.
const movies = [
{ id: 1, title: "Batman", ratings: 8 },
{ id: 2, title: "Avengers", ratings: 8 },
{ id: 1, title: "Dune", ratings: 9 }
];
const [myObjects, setMyObjects] = useState(movies);
return (
<div>
  {myObjects.map((movie) => (
    <p>{movie.title}</p>
  ))}
  <ChangeMovie changeMovieList={setMyObjects}/> // This is the child component which handle changing the state of Movie(Parent). Here pass the state change function as a prop(changeMovieList) to child. Then we can use that to change the state inside that component.
</div>
);
};

export default Movie;


const ChangeMovie = (props) => { // This is the child component.
const changeList = () => {
props.changeMovieList([ // here we change the state of Movie(Parent Component) inside child using the function passed.
  { id: 1, title: "Superman", ratings: 8 },
  { id: 2, title: "Titanic", ratings: 8 },
  { id: 1, title: "Fast & Furious 8", ratings: 9 }
]);
};

return (
<>
  <button onClick={changeList}>Change Movie List</button>
</>
);
};

export default ChangeMovie;

Check this demo sandbox I created to elaborate this.

Upvotes: 0

tgikf
tgikf

Reputation: 557

If you want the parent component to be able to change the state, you'd either

  • Make myObjects a state of the parent component or
  • Initialize the myObjects state with the props passed from the parent component

Unless having the state inside the component prevents you from making your component a pure component, I'd typically recommend the latter:

const {
  useState
} = React;

const MyComponent = (props) => {
  const [myObjects, setMyObjects] = useState(props.myObjects)

  return ( 
    <div>Rendering from MyComponent
      <ul>
        {myObjects.map(o => <li>{o}</li>)}
      </ul>
    </div>
  );
};

const MyParentComponent = () => {
  const objects = ['object1 from MyParentComponent', 'object2  from MyParentComponent', 'object3  from MyParentComponent'];
  return (<MyComponent myObjects={objects} />);
}

ReactDOM.render( <MyParentComponent / > ,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions