react component lifecycle to execute before render - reactjs

I want to have some check before react component is rendered..
Lets say I have a component which renders something like
render() {
const {videos, actions} = this.props
return (
<div>
<List />
</div>
)
}
But before rendering the list I want to have custom check on the list...
What I meant to say is before showing the <List /> component I want to have some check and only after that check is finished I want to show the component with render method ..
The check I am mentioning here might be anything like the list should be 10 in count or anything.
I have tried following
componentWillUpdate(){
console.log("Component will update")
}
shouldComponentUpdate(){
console.log("Should component update")
}
From the react documentation I knew that both of them are called before render... But when I do this nothing is printed in the console but render method is called..
I know that componentWillMount() is called before render but what I want is a function which calls render only after the completion or return from the function
Hope you understand and need help

In the render() function you can run checks before you return the JSX/elements:
render() {
// run any checks here
const {videos, actions} = this.props
return (
<div>
<List />
</div>
)
}

You can return early from render with a different result. When the props change, render will be called again with newer props.
class MyComponent {
render() {
const { items } = this.props;
if (items.length < 10) return <span>Loading...</span>;
return <List items={items} />;
}
}

Related

How do I implement an onClick method in one child component that updates the text in a sibling component, based on the state in App.js?

Every row in my SideMenuContainer corresponds to an object from schema.json, showing only the name property. The behavior I want is that when a row is clicked, the PaneViewContainer toggles to display the name and other properties of that respective object from the json.
In App.js, the data is passed to SideMenuContainer like so:
render() {
return (
<MainContainer>
<SideMenuContainer genInfoList={this.state.genInfoList}/>
<PaneViewContainer genInfoList={this.state.genInfoList}/>
</MainContainer>
);
}
In SideMenuContainer, every row is populated like this:
render() {
return (
<SideMenuPane>
<SideMenu>
<div>
<h2>GenInfo</h2>
{this.props.genInfoList.map(genInfoElement => {
return (
<SideMenuRow>
{genInfoElement.name}
</SideMenuRow>
);
})}
</div>
</SideMenu>
</SideMenuPane>
);
}
What I want to do is change the genInfoList information being displayed in the PaneViewContainer based on which row is clicked in its sibling, SideMenuContainer.
The entire genInfoList data is being passed to both sibling components from their parent App.js, so I want to change which portion of that data is loaded in the Pane based on the row clicked in the SideMenu.
I thought about using the Context API, but I'm having trouble figuring out how to implement it for this purpose. Any ideas?
If I understand correctly you have your information stored in the parent element of both components then you can just pass a function down as a prop and have all of your logic stored in the parent element.
changeInfoList = id => {
//change your info list based on id or index or whatever
this.setState({
//your new list
})
}
render() {
return (
<MainContainer>
<SideMenuContainer changeInfoList={this.changeInfoList} genInfoList={this.state.genInfoList}/>
<PaneViewContainer genInfoList={this.state.genInfoList}/>
</MainContainer>
);
}
and then call changeInfoList from your component with props
render() {
return (
<SideMenuPane>
<SideMenu>
<div>
<h2>GenInfo</h2>
{this.props.genInfoList.map(genInfoElement => {
return (
<SideMenuRow>
{genInfoElement.name}
<button onClick={this.props.changeInfoList(genInfoElement.id)>CLick Me</button>
</SideMenuRow>
);
})}
</div>
</SideMenu>
</SideMenuPane>
);
}
this is commonplace in react as you should have smart components and dumb components. When you have components not in the same tree or spread far away then the context api is very useful. In your case I don't think its necessary.
Without external state management, you would have to pass down a callback (as props), so the children can update the parent's state.
As the components get far away from each other, this pattern can get annoying (passing down callbacks each time). That's where external state management can help.
Here's a simple (and untested) example using a callback:
class Counter extends React.Component {
constructor() {
super();
this.increment = this.increment.bind(this);
this.state = {count: 0};
}
increment() {
let count = thist.state.count;
this.setState({count: count + 1});
}
render() {
return <div>
<CounterButton increment={this.increment}/>
<CounterDisplay count={this.state.count}/>
</div>;
}
}
class CounterButton extends React.Component {
render() {
let increment = this.props.increment;
return <button onClick={increment}>Plus One</button>;
}
}
class CounterDisplay extends React.Component {
render() {
let count = this.props.count;
return <span>{count}</span>;
}
}

Unable to prevent rerender with shouldComponentUpdate() or with PureComponent

In /home/:id I have a <LogButtons/> when its clicked logOn() get called so logsignPopUp variable become a <logForm/> component.
In the same page I have a <IframeYoutubeComponent/>, I want to prevent it to rerender when the <logForm/> pop on the screen so the video isn't reloaded.
home.js :
export default class Home extends Component {
constructor(props) {
super(props);
this.state = { logsign: "" };
this.logOn = this.logOn.bind(this);
this.signOn = this.signOn.bind(this);
}
logOn() {
this.setState({ logsign: "log" });
}
render() {
let logsignPopUp = this.props.logsign === "log" ? <LogForm/> : this.state.logsign;
let homePage =
<div>
{logsignPopUp}
<div>
<LogButtons logOn={this.logOn}/>
</div>
<div>
<IframeYoutubeComponent paramsId={this.props.match.params.paramsId}/>
</div>
</div>;
return (
<div>
<Route exact path="/home/:id" component={() => <div>{homePage}</div> } />
</div>
);
}
}
iframeYoutubeComponent.js :
export class IframYoutubeComponent extends Component {
render() {
//this.props.youtube come from Redux state
let src = this.props.youtube.find(el => el.youtubeId === this.props.paramsId);
return (
<iframe src={"https://www.youtube.com/embed/" + src}></iframe>
);
}
}
I tried to return false in shouldComponentUpdate() but its not even called :
shouldComponentUpdate() {
console.log("test");
return false;
}
I tried to use a PureComponent for <IframeYoutubeComponent/> but the video still reload when the <logForm/> pop.
I tried to add key to my components and also tried to put this.state.logsign in Redux but nothing worked out.
I started react since 2 months so I might miss something obvious but I can't find out what... Any idea ?
That's because you are passing an arrow function in a component prop to the Route. This way everytime you generate a new function.
You should pass a react component in this prop or at least a function that returns JSX but this function should be defined once. For example as a class method.
Something like:
<div>
<Route exact path="/home/:id" component={this.renderHomePage} />
</div>
But then of course you have to refactor your logic regarding this logsign prop.

react component order for fetching data

I am new in react so maybe this is simple question.
I have two components that are calling database - CallsCharts and CallsList. I want to first render CallsCharts and when it finish I want to query database for CallsList. How can I do that? When I leave it like this, CallsList is always first to load.
Can I somehow choose priority?
render() {
return (
<div className="container-fluid">
<CallsCharts/>
<CallsList/>
</div>
);
}
You can compose them. CallsList can be a child of CallsCharts. In this way, CallsCharts will only render CallsList when CallsCharts has finished querying api.
As simple as:
class CallsCharts extends Component {
componentDidMount () {
// fetch charts
}
render() {
const { charts } = this.props;
if (checkChart(charts)) {
return <CallsList />
}
}
}
Compose your components and implement them as function component. this way you can return a promise and wait for the resolve in your child component.
render() {
return (
<div className="container-fluid">
<CallsCharts>
{({promise}) => <CallsList promise={promise}/>}
</CallsCharts>
</div>
);
}

Call a child component function from parent class in react.js [duplicate]

I have simple component called List which is a simple ul with some li inside. Each li is a simple component.
I have other parent component which render one input field and the List component. Tapping on Send key I catch text of input field. I want to call for example a function called handleNewText(inputText) but this function need to stay inside List component because the state I use to populate other li components live in List component.
I don' t want to refactor List and MyParent component passing the manage of data from List to MyParent.
first is parent and second is child
class TodoComp extends React.Component {
constructor(props){
super(props);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
componentDidMpunt(){
console.log(this._child.someMethod());
}
handleKeyPress(event){
if(event.key === 'Enter'){
var t = event.target.value;
}
}
render(){
return (
<div>
<input
className="inputTodo"
type="text"
placeholder="want to be an hero...!"
onKeyPress={this.handleKeyPress}
/>
<List/>
</div>
);
}
}
export default class List extends React.Component {
constructor() {
super();
this.flipDone = this.flipDone.bind(this);
this.state = {
todos: Array(3).fill({ content: '', done: false})
};
}
flipDone(id) {
let index = Number(id);
this.setState({
todos: [
...this.state.todos.slice(0, index),
Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
...this.state.todos.slice(index + 1)
]
});
}
render() {
const myList = this.state.todos.map((todo, index) => {
return (
<Todo key={index}
clickHandler={this.flipDone}
id={index}
todo={todo}
handleText={this.handleText}
/>
);
})
return (
<ul className="list">
{myList}
</ul>
);
}
ReactDOM.render(<TodoComp />,document.getElementById('myList'));
You need to make use of refs to call a function in the child component from the parent component
render the List component from parent as
<List ref="myList"/>
and then access the handleNewText() function as this.refs.myList.handleNewText()
UPDATE:
Strings refs are no longer recommended by React, you should rather use ref callbacks, check this
<List ref={(ref) => this.myList=ref}/>
and then access the child function like
this.myList.handleNewText()
Adding to #shubham-khatri solution:
If you are referencing a connected child component...
a. That child must say withRef: true in the (4th) config parameter:
#connect(store => ({
foo: store.whatever
…
}),null,null,{ withRef: true })
b. Access is through getWrappedInstance() (note, that getWrappedInstance also needs to be called ())
getWrappedInstance().howdyPartner()
I started learning React when functional component came out. Another way I experimented with some success is returning functions that you want to access as closures within a JSON. I like this method because closure is a construct of Javascript and it should still work even if React is updated yet again. Below is an example of child component
function Child(){
//declare your states and use effects
const [ppp, setPPP] = useState([]);
const [qqq, setQQQ] = useState(2);
//declare function that you want to access
function funcA(){ /*function to interact with your child components*/}
function funcB(){ /*function to interact with your child components*/}
//pure React functional components here
function Content(){
//function that you cannot access
funcC(){ /*.....*/}
funcD(){/*.......*/}
//what to render
return (
<div>
{/* your contents here */}
</div>
)
}
//return accessible contents and functions in a JSON
return {
content: Content, //function for rendering content
ExposeA: funcA, //return as a closure
ExposeB: funcB, //return as a closure
}
}
Below is an example of how you would render the child contents within the parent
function Parent(){
let chi = Child();
let ChildContent = chi.Content;
//calling your exposed functions
//these function can interacts with the states that affects child components
chi.ExposeA();
chi.ExposeB();
//render your child component
return (<div>
<div> {/* parent stuff here */</div>
<div> {/* parent stuff here */</div>
<ChildContent {/*Define your props here */} />
</div>)
}

Call child component method from parent in react

I have simple component called List which is a simple ul with some li inside. Each li is a simple component.
I have other parent component which render one input field and the List component. Tapping on Send key I catch text of input field. I want to call for example a function called handleNewText(inputText) but this function need to stay inside List component because the state I use to populate other li components live in List component.
I don' t want to refactor List and MyParent component passing the manage of data from List to MyParent.
first is parent and second is child
class TodoComp extends React.Component {
constructor(props){
super(props);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
componentDidMpunt(){
console.log(this._child.someMethod());
}
handleKeyPress(event){
if(event.key === 'Enter'){
var t = event.target.value;
}
}
render(){
return (
<div>
<input
className="inputTodo"
type="text"
placeholder="want to be an hero...!"
onKeyPress={this.handleKeyPress}
/>
<List/>
</div>
);
}
}
export default class List extends React.Component {
constructor() {
super();
this.flipDone = this.flipDone.bind(this);
this.state = {
todos: Array(3).fill({ content: '', done: false})
};
}
flipDone(id) {
let index = Number(id);
this.setState({
todos: [
...this.state.todos.slice(0, index),
Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
...this.state.todos.slice(index + 1)
]
});
}
render() {
const myList = this.state.todos.map((todo, index) => {
return (
<Todo key={index}
clickHandler={this.flipDone}
id={index}
todo={todo}
handleText={this.handleText}
/>
);
})
return (
<ul className="list">
{myList}
</ul>
);
}
ReactDOM.render(<TodoComp />,document.getElementById('myList'));
You need to make use of refs to call a function in the child component from the parent component
render the List component from parent as
<List ref="myList"/>
and then access the handleNewText() function as this.refs.myList.handleNewText()
UPDATE:
Strings refs are no longer recommended by React, you should rather use ref callbacks, check this
<List ref={(ref) => this.myList=ref}/>
and then access the child function like
this.myList.handleNewText()
Adding to #shubham-khatri solution:
If you are referencing a connected child component...
a. That child must say withRef: true in the (4th) config parameter:
#connect(store => ({
foo: store.whatever
…
}),null,null,{ withRef: true })
b. Access is through getWrappedInstance() (note, that getWrappedInstance also needs to be called ())
getWrappedInstance().howdyPartner()
I started learning React when functional component came out. Another way I experimented with some success is returning functions that you want to access as closures within a JSON. I like this method because closure is a construct of Javascript and it should still work even if React is updated yet again. Below is an example of child component
function Child(){
//declare your states and use effects
const [ppp, setPPP] = useState([]);
const [qqq, setQQQ] = useState(2);
//declare function that you want to access
function funcA(){ /*function to interact with your child components*/}
function funcB(){ /*function to interact with your child components*/}
//pure React functional components here
function Content(){
//function that you cannot access
funcC(){ /*.....*/}
funcD(){/*.......*/}
//what to render
return (
<div>
{/* your contents here */}
</div>
)
}
//return accessible contents and functions in a JSON
return {
content: Content, //function for rendering content
ExposeA: funcA, //return as a closure
ExposeB: funcB, //return as a closure
}
}
Below is an example of how you would render the child contents within the parent
function Parent(){
let chi = Child();
let ChildContent = chi.Content;
//calling your exposed functions
//these function can interacts with the states that affects child components
chi.ExposeA();
chi.ExposeB();
//render your child component
return (<div>
<div> {/* parent stuff here */</div>
<div> {/* parent stuff here */</div>
<ChildContent {/*Define your props here */} />
</div>)
}

Resources