All data comes into console but does not show into app
import React from 'react'
const Question_Answer_model = (props) => {
console.log(props.data)
const newvar = props.data.map((item) => {
return (
<li>{item.question_text}</li>
)
})
return (
<div>
<div>
<h2>Question And Answers...</h2>
{newvar}
</div>
</div>
)
}
export default Question_Answer_model
this is my consoledata which shows in console
here all comes into array in console
I think this will help you
import React from 'react'
const Question_Answer_model = (props) => {
//console.log(props)
const newvar = props.data.map((item) => {
return (
<li>{item.data.question_text}</li>
)
})
return (
<div>
<div>
<h2></h2>
{newvar}
</div>
</div>
)
}
export default Question_Answer_model
const newvar = props.data.map((item) => {
return (
<li>{item.question_text}</li>
)
})
This should be wrapped inside useCallback/useMemo/memberFunction.
It is not displaying because it is rendering for the first time and rendering when you get data.
Solved E.g
const { data } = props;
const newvar = useCallback(() => {
data.map((item) => {
return (
<li>{item.question_text}</li>
)
})
}, [data ])
use newvar inside return
Related
For the purposes of documenting our library, I want to convert a React Component function to JSX. For example, if we have a rendered Button component, I want to show the code for how it's constructed.
One solution could be to read Button.jsx as plain text but I feel like there should be a better solution.
// Button.jsx
export const Button = (props) => (
<button {...props}><Icon name={props.icon}/>{props.children}</button>
)
// ButtonDocs.jsx
import { Button } from 'components/Button';
const Docs = (props) => {
const renderedButton = <Button icon='home'>Hello</Button>
// Here I'd expect this function to return something like:
// `<button><Icon name="home"/>Hello</button>`
const buttonJSX = someFunctionToGetJSX(renderedButton)
return (
<div>
{renderedButton}
<code>
{buttonJSX}
</code>
</div>
)
}
Do this in Button component
const Button = (props) => {
const buttonRef = useRef();
const [jsxEl, setJsxEl] = useState("");
useEffect(() => {
let jsxArray = [];
for (let i = 0; i < buttonRef.current.children.length; i++) {
jsxArray.push(`${buttonRef.current.children[i].innerHTML}`);
}
jsxArray.join(",");
setJsxEl(jsxArray);
props.onJsxFunc(jsxEl);
}, [buttonRef]);
return (
<Fragment>
<div ref={buttonRef}>
<button {...props}>
<Icon name={props.icon} />
{props.children}
</button>
</div>
</Fragment>
);
};
export default Button;
Then in ButtonDocs component do the below.
// ButtonDocs.jsx
import { Button } from 'components/Button';
const Docs = (props) => {
const renderedButton = <Button onJsxFunc={(el) => showJsxElements(el)} icon='home'>Hello</Button>
const jsxCode = useRef();
const showJsxElements = (el) => {
jsxCode.current.innerText += `${el}`;
};
return (
<div>
{renderedButton}
<code>
<div ref={jsxCode}></div>
</code>
</div>
)
}
I have 2 buttons, Single Component and Multiple Component.
When I click on Multiple Component, I expect it to add 3 components, but it adds only 1.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react-lite";
function App() {
const [component, setComponent] = useState([]);
useEffect(() => {});
const newArray = [1, 2, 3];
const Test = observer(() => {
return (
<div>
<p>Test</p>
</div>
);
});
const Test2 = observer(() => {
return (
<div>
<p>Test2</p>
</div>
);
});
const Test3 = observer(() => {
return (
<div>
<p>Test3</p>
</div>
);
});
async function MultipleComponent() {
newArray.map(async (x) => {
if (x === 1) {
await setComponent([...component, Test]);
} else if (x === 2) {
await setComponent([...component, Test2]);
} else {
await setComponent([...component, Test3]);
}
console.log(x);
});
}
return (
<div>
{component.map((Input, index) => (
<Input components={component} key={index} />
))}
<button onClick={() => setComponent([...component, Test])}>
Single Component
</button>
<button onClick={() => MultipleComponent()}>Multiple Component</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
codensadbox: https://codesandbox.io/s/react-hooks-useeffect-forked-edmgb5
There is no point in using await on setState, nowhere the docs say it is a good idea.
On the other hand you need to use version of setState which accepts an updater function, there you can get previous state.
setComponent(ps=>[...ps, Test2])
Also, I don't have link to official docs, but I am not sure storing components inside state is good idea either. You could store some identifier in state which indicates which component it is and then render that one when time comes. Here is what I mean by this:
let Test1 = (props) => {
return <div>1</div>;
};
let Test2 = (props) => {
return <div>2</div>;
};
let GeneralComponent = (props) => {
if (props.comp === '1') return <Test1 />;
if (props.comp === '2') return <Test2 />;
return null;
};
export default function App() {
let [comp, setComp] = React.useState('1');
return (
<div onClick={() => setComp(comp === '1' ? '2' : '1')}>
<GeneralComponent comp={comp} />
</div>
);
}
The GeneralComp accepts an identifier of which component to render, which is stored in state in parent.
Iam doing one of the react assignment and I am stuck on the last part of this assignment. The question is like this: Improve on the application in the previous exercise, such that when the names of multiple countries are shown on the page there is a button next to the name of the country, which when pressed shows the view for that country. Here is my code. I tried some functions but couldnot get it so I wonder if someone can help me to cope with this last part..Thank you
import React, { useState, useEffect } from "react";
import axios from "axios";
import ReactDOM from "react-dom";
const App = () => {
const [countries, setCountries] = useState([]);
const [filter, setFilter] = useState("");
const [select, setSelected] = useState([]);
//console.log(countries);
useEffect(() => {
axios.get("https://restcountries.eu/rest/v2/all").then((response) => {
setCountries(response.data);
});
}, []);
const searchHandler = (e) => {
setFilter(e.target.value);
//console.log(filter);
const selected_countries = countries.filter((item) => {
const letter_case=item.name.toLowerCase().includes(filter.toLowerCase())
return letter_case
});
setSelected(selected_countries);
};
const countryLanguages = (languages)=>
languages.map(language => <li key={language.name}>{language.name}</li>)
const showCountries = () => {
if (select.length === 0) {
return <div></div>
} else if (select.length > 10) {
return "Find the specific filter";
}
else if(select.length>1 && select.length<10){
return (select.map(country=>
<div key={country.alpha3code}>{country.name}
<button>Show</button>//this part
</div>)
)
}
else if(select.length===1){
return(
<div>
<h1>{select[0].name}</h1>
<div>capital {select[0].capital}</div>
<div>population {select[0].population}</div>
<h2>languages</h2>
<ul>{countryLanguages(select[0].languages)}</ul>
<img src={select[0].flag} width="100px"/>
<h2>Weather in {select[0].capital}</h2>
</div>
)
}
};
return (
<div>
<h1>Countries</h1>
find countries: <input value={filter} onChange={searchHandler} />
{showCountries()}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
Create a separate component.
const SingleCountry = ({name}) => {
const [ showDetails, setShowDetails ] = useState(false);
const toggleDetails = () => setShowDetails(!showDetails); //toggles the variable true/false
return ( <div>
<button onClick={toggleDetails}>Show Details</button>
{ /* renders the <div> only if showDetails is true */ }
{ showDetails && <div>These are the details of the country {name}</div> }
</div>)
}
Edit your showCountries component to use the new component.
const showCountries = () => {
if (select.length === 0) {
return <div></div>
} else if (select.length > 10) {
return "Find the specific filter";
}
else if(select.length>1 && select.length<10){
return (select.map(country=> <SingleCountry key={country.alpha3code} name={country.name} />
)
}
const ParentComponent = () => {
const [cache,setCache] = useState({});
const data = [{url:"http://.."} , {url:"http://.."} , {url:"http://.."}];
return (
data.map( item,ind => (<ChildComponent item={item} setCache={setCache} cache={cache} /> ) )
)
}
const ChildComponent = ({item,setCache,cache}) => {
const [img,setImg] = useState(null);
useEffect(() => {
const setVal = async () => {
const val = await getProfilePic(item.url); //api
setCache({...cache ,[item.url]:val})
setImg(val);
};
if(cache[item.url])
{ return setImg(cache[item.url]) }
else { setVal(); }
} ,[])
return (
<div> <img src={img} /> </div>
)
}
here the url in the array variable data can be the same. In that case, it should not call the API again but should take from the variable cache.
The problem in the above case is when the second item in the array is used for rendering child component, it's not getting the value which we set using the in the first render(using the first item in the array). How can I achieve this ?
As, the Title says... I can get the console to echo the array, but It won't render on my navigation bar.
From App.js:
unValidatedUserButtons = ["Search", "Login", "Register"];
render() {
return (
<Layout>
<Header />
<Topnav buttons={this.unValidatedUserButtons}/>
</Layout>
)
}
to TopNav:
buttonHandlerTnav = (buttonPass) => {
let newButtons = [...buttonPass];
this.setState({buttons: newButtons});
this.setState({needButtons: false});
}
render(){
if (this.state.needButtons)
this.buttonHandlerTnav(this.props.buttons);
return (
<div className={classes.TopNav}>
<MenuButton />
<AccountButtons
buttonPass={this.state.buttons} />
</div>
);
}
Then to AccountButtons:
const buttonHandlerAccount = (newButtons) => { newButtons.map((Button, index) => {
return (<button key={index}>{Button}</button>)
});
}
const accountButtons = (props) => {
// console.log(props.buttonPass);
return (
<div className={classes.AccountButtons}>
{buttonHandlerAccount(props.buttonPass)}
</div>
)
}
If anyone could help me get my buttons to render, it will be very much appreciated.
buttonHandlerAccount is missing a return statement.
// Button Handler Account.
const buttonHandlerAccount = (newButtons) => {
return newButtons.map((Button, index) => <button key={index}>{Button}</button>)
}
It looks like you're missing a return in your functional component. Try this to resolve your problem:
const buttonHandlerAccount = (newButtons) => {
return newButtons.map((Button, index) => {
return (<button key={index}>{Button}</button>)
});
}
Or, the short hand equivalent:
const buttonHandlerAccount = (newButtons) => (newButtons.map((Button, index) => {
return (<button key={index}>{Button}</button>)
}))