I tried to do task below, but i am stuck, How can I structure my components in a way that, it will be possible for nesting same component inside component.
App.js file
render () {
return (
<main className="wrapper">
<div className="row">
<Container addBox = { this.addBox }
boxes = {this.state.containers}
changeColor={this.changeColor}
addContainer = {this.addContainer}
containers={this.state.containers}/>
</div>
</main>
);
}
Like you add Container in app.js, create Box component and add it to Container.js, set the props as you did in this one, something like this:
import Container from "./Container.js"
state={ data1 : "something" }
render () {
return (
<main className="wrapper">
<div className="row">
<Container addBox = { this.addBox }
propsAgain={this.state.data1}
changeColor={this.changeColor}
addContainer = {this.addContainer}
containers={this.state.containers}/>
</div>
</main>
);
Container.js:
import Box from "./Box.js"
render () {
const{propsAgain}=this.props // we pass it upper again
return (
<div className="row">
<Box props1 = {propsAgain}
</div>
);
Box.js:
render () {
const {props1, props2} = this.props // these are props to pass to parent component
return (
<div>{props1}</div>
);
If you want to pass the grandchildren components' data to the upper component, you can pass the props to one step up, define props again and pass it to one step up again
Related
I have three components inside of the App component:
<Header/>
<Boroughs/>
<Map/>
function App() {
const [selectedNhood, setSelectedNhood] = useState("");
let neighborhoodData;
if (selectedNhood) {
neighborhoodData = boroughsData.filter(item => item.Name === selectedNhood);
}
return (
<div className="App">
<Header labels={["About", "Log in", "Register"]} />
<h1>
Explore Neighborhoods:
</h1>
<Boroughs
neighborhoods={neighborhoods}
onSelectedChange={setSelectedNhood}
/>
<Map neighborhoodData={neighborhoodData} />
</div>
);
}
The <Boroughs/> takes setSelectedNhood as a prop. Inside the <Boroughs/> compoenent I have another compoenent called <NeighborhoodsLabels/> and this compoenent also takes setSelectedNhood as a prop, which is then used on a click event, like so:
const NeighborhoodsLabels = ({ neighborhoods, onSelectedChange }) => {
const svgDivContainer = document.getElementsByClassName(
"svg-div-container"
)[0];
const onNeighborhoodClick = (neighborhood) => {
onSelectedChange(neighborhood); // <----------
svgDivContainer.scrollIntoView({
behavior: "smooth"
});
};
const renderedNeighborhoods = neighborhoods.map((item, index) => {
return (
<div
onClick={() => {
onNeighborhoodClick(item);// <----------
}}
className="neighborhood"
key={item}
>
{item}
</div>
);
});
return <div className="neighborhoodsContainer">{renderedNeighborhoods}</div>;
};
When the click event inside <NeighborhoodsLabels/> fires setSelectedNhood, the entire <App/> component will re-render, as it is exptected.
However, this really affects the performance of my App, and I need it to re-render because the <Map/> component uses the data that is changed when setSelectedNhood is trigered in the <NeighborhoodsLabels/>.
So my question is, how to improve performance when the state of the <App/> is changed from a component that is nested two levels down (<NeighborhoodsLabels/>) and then that change is used on another component that is in the <App/> component, which in this case is the <Map/>
Thanks!
I have a navbar component that I created for react.
When I call this component on different pages, I need to change the classNames.
For example : I want my "" component to have a different class on one page and a different class on another page.
const ServicesCiso = () => {
return (
<div className="hero">
<NavBar/>
<div className...
How can i add className in this code ?
You can pass the className as props to this component and pass the preferred className on the page you are rendering it
const ServicesCiso = ({ className }) => {
return (
<div className={className}>
<NavBar/>
<div className...
<ServicesCiso className="my-class-name" />
You should pass the className from out side to your component via props however you also need a default class in init case
I have suggestion this library
https://www.npmjs.com/package/classnames ( combine classes )
example
View
- ServicesCiso.js
- ServicesCiso.css
import ./ServicesCiso.css;
import cn from('classnames');
const ServicesCiso = (props) => {
const {className} = props;
return (
<div className={cn('hello', className}}>
</div>
)
}
I used a component as a child as follows, and in the parent component, ie ShowBodyQuestionsForArchive component, I used the child component as follows: {children}
in ShowBodyQuestionsForArchive component(parent) i have another componet As follows:
I want to change the data of ShowImage component in ShowComparetiveItemsForArchive component(child), which is displayed as {children}
const ShowComparativeQuestionForArchive = ({question, number, items}) => {
changeShowImage(){
//changedData
}
return(
<ShowBodyQuestionForArchive question = {question} number = {number}>
<ShowComparativeItemsForArchive changeShowImage = {changeShowImage()} number = {number} items = {items} />
{
showImage ? <ShowImage {changedData} /> //example
}
<ShowBodyQuestionForArchive/>
)
}
Now call the prop (changeShowImage) in ShowComparativeItemsForArchive
I have 2 components. I want to keep component A clean, hence I don't wish to use useState in it, I wish to use useState in component B, but since the component B isn't a hook (because it return the jsx as well), how can I call stateHandler in component A?
const ComponentA = () => {
return (
<div>
<ComponentB />
<button onClick={()=>{
//what to do here to control the state of component B?
}}>show component B</button>
</div>
)
}
const ComponentB = () => {
//I don't want to move this setShowBlock to index.js for clean code purpose
const [showBlock, setShowBlock] = useState(false)
return (
<div>
{showBlock && <div>component B</div>}
</div>
)
}
https://stackblitz.com/edit/react-ggtt87?file=index.js
you can use context as central store,
in the context you create the useState hook with showBlock and setShowBlock and then you can change it from component A
const ComponentA = () => {
const {setShowBlock} = useContext(MyContext)
return (
<div>
<ComponentB />
<button onClick={()=>{
here call setShowBlock and change it
}}>show component B</button>
</div>
)
}
Basically new to React, I'm a bit confused on how to properly pass states between components. I found a similar question already React – the right way to pass form element state to sibling/parent elements?
but I wonder if you can give me a specific answer for the code below.
Currently the structure of the app includes:
parent component - App
2 childs: SearchBar and RecipesList
The goal is to make an async search on my Meteor collection and display only the recipes that match the search term.
Right now, I'm just showing all the recipes in my Meteor collection.
I've created a stateful component named SearchBar which holds the input value as this.state.term. The idea is to pass the state to RecipesList but I'm not sure if it's the right thing to do. Alternatively I'd let App deal with the state and passing it to the childs. I believe this is a very common scenario, how do you do it?
App
class App extends Component {
render( ) {
return (
<div>
<Navbar/>
<SearchBar/>
<RecipesList/>
</div>
);
}
}
SearchBar
export default class SearchBar extends Component {
constructor( props ) {
super( props );
this.state = {
term: ''
};
}
onInputChange( term ) {
this.setState({ term });
}
render( ) {
return (
<div className=" container-fluid search-bar">
<input value={this.state.term} onChange={event => this.onInputChange(event.target.value.substr( 0, 50 ))}/>
Value: {this.state.term}
</div>
);
}
}
RecipesList
const PER_CLICK = 5;
class RecipesList extends Component {
componentWillMount( ) {
this.click = 1;
}
handleButtonClick( ) {
Meteor.subscribe('recipes', PER_CLICK * ( this.click + 1 ));
this.click++;
}
renderList( ) {
return this.props.recipes.map(recipe => {
return (
<div key={recipe._id} className="thumbnail">
<img src={recipe.image} alt="recipes snapshot"/>
<div className="caption">
<h2 className="text-center">{recipe.recipeName}</h2>
</div>
</div>
);
});
}
render( ) {
return (
<ul className="list-group">
{this.renderList( )}
<div className="container-fluid">
<button onClick={this.handleButtonClick.bind( this )} className="btn btn-default">More</button>
</div>
</ul>
);
}
}
// Create Container and subscribe to `recipes` collection
export default createContainer( ( ) => {
Meteor.subscribe( 'recipes', PER_CLICK );
return {recipes: Recipes.find({ }).fetch( )};
}, RecipesList );
App
class App extends Component {
constructor(props, ctx){
super(props, ctx)
this.state = {
searchQuery: ''
}
this.searchInputChange = this.searchInputChange.bind(this)
}
searchInputChange(event) {
this.setState({
searchQuery: event.target.value.substr( 0, 50 )
})
}
render( ) {
const { searchQuery } = this.state
return (
<div>
<Navbar/>
<SearchBar onChange={this.searchInputChange} value={searchQuery}/>
<RecipesList searchQuery={searchQuery}/>
</div>
)
}
}
The App component takes care of the state and this is then passed down to the children as props the seach term is available to RecipesList through props.searchQuery.
The searchInputChange handler is passed down to the SearchBar as props.
SearchBar
export default const SearchBar = ({value, onChange}) => (
<div className=" container-fluid search-bar">
<input value={value} onChange={onChange}/>
Value: {value}
</div>
)
Since the SearchBar delegated state to the parent component, we can use a stateless react component as we only need information from the props to render it.
In general it is always best to have a logical or stateful or controller component take care of state and the logic, this component then passes down state and methods to presentational or view components which take care of what the user sees and interacts with.
Define the state term up in to the App component.
Also write the handleInput function and pass it to the SearchBar component as porps
handleInput(val) {
this.setState({
term: val,
});
}
When something in the search bar is typed(onKeyUp) add the listener handleInput.
Also create <RecipesList searchQuery={this.state.term}/>
now in the render function RecipesList filter out the recipes you want to display from your list