How to get value of a component to another component - javascript

I am creating a Project where I need to get value of a component state value to another component.
How can I get the value?
Information
Both are functional component.
I need to send data from A (state) to B(state).
A state data are set from react dropdown menu.Which is a button.
I don't use Link or Route to A dropdown that's why I can't get it with useParams()
I need to set value in B component which will fetch data with passing language.
I have import all needed things & don't have any warnings & error.
Code of component A
Send value from this language state to B
const A = () => {
const [language, setLanguage] = useState('en');
return (
<Navbar expand="xl" bg='light' expand={false}>
<Container>
<DropdownButton id="dropdown-basic-button" title={<MdOutlineLanguage />}>
<Dropdown.Item as="button" onClick={() => setLanguage('en')}>English</Dropdown.Item>
<Dropdown.Item as="button" onClick={() => setLanguage('ar')}>العربية</Dropdown.Item>
<Dropdown.Item as="button" onClick={() => setLanguage('bn')}>বাংলা</Dropdown.Item>
</DropdownButton>
</Container>
</Navbar>
)
};
export default A
Code of Component B
I need to get here A state value & set it to B state. Then pass to useGetDataQuery & fetch data.
const B = () => {
let [language, setLanguage] = useState('en')
const { data } = useGetDataQuery({language })
return (
<>
</>
)
}
export default B
Redux Section
I'm using readux & #reduxjs/toolkit to store fetch data. Can I store my language data to here. Than how can get to from anywhere of my component.
react-rotuer-dom v6
export default configureStore({
reducer: {
[dataOne.reducerPath]: dataOne.reducer,
[data2.reducerPath]: dataTwo.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false
}).concat([dataOne.middleware, dataTwo.middleware]),
})

Maybe instead of using useState, you can use a global state by using useContext because I think your language will be use on several places as request body and of course to edit the state value, you can combine it with useReducer.
// UPDATE
working code: https://codesandbox.io/s/sleepy-monad-21wnc
MyContext
import { useReducer, useContext, createContext } from "react";
const initialValue = {
language: "id"
// other: "value",
};
const AppContext = createContext(initialValue);
const AppReducer = (state, action) => {
switch (action.type) {
case "CHANGE_LANGUAGE":
return {
...state,
...action.payload
};
default:
return state;
}
};
const MyContext = ({ children }) => {
const [state, dispatch] = useReducer(AppReducer, initialValue);
return (
<AppContext.Provider value={[state, dispatch]}>
{children}
</AppContext.Provider>
);
};
export const useAppContext = () => useContext(AppContext);
export default MyContext;
this is the context and reducer component later on use in App.js
App.js
import A from "./A";
import B from "./B";
import MyContext from "./MyContext";
import "./styles.css";
export default function App() {
return (
<MyContext>
<div className="App">
<A />
<B />
</div>
</MyContext>
);
}
A.js
import { useAppContext } from "./MyContext";
const A = () => {
const [globalState, dispatch] = useAppContext();
const onChange = (e) => {
dispatch({
type: "CHANGE_LANGUAGE",
payload: {
[e.target.name]: e.target.value
}
});
};
return (
<>
<p>Start Of Component A </p>
<input value={globalState.language} name="language" onChange={onChange} />
<p>End Of Component A </p>
</>
);
};
export default A;
B.js
import { useAppContext } from "./MyContext";
const B = () => {
const [globalState, dispatch] = useAppContext();
return (
<>
<p>Start Of Component B </p>
<h2>Language Val : {globalState.language}</h2>
<p>End Of Component B </p>
</>
);
};
export default B;

Related

Create State from another context state in function component

I am trying to get a state from context and initialize to new state. But the newly created state is not initializing. Help me out.
import { ProductsContext } from "../../../store/ProductsContext";
const EditVariant = () => {
let { id } = useParams();
const navigate = useNavigate();
const { getProductsById, singleProduct } = useContext(ProductsContext);
const [productName, setProductName] = useState(singleProduct.productName);
console.log(productName) // This is undefined
useEffect(() => {
getProductsById(id);
}, []);
return (
<Form
productName={productName}
setProductName={setProductName}
/>
</div>
);
};
export default EditVariant;
The Form component gets the undefined value. The value is not initializing properly.
You need to export your UserContext so it can be imported into the components that need it:
export const UserContext = React.createContext();
function App() {
const [name, setName] = useState('Name');
return (
<UserContext.Provider value={{ name, setName }}>
<Home />
</UserContext.Provider>
);
}
Afterward, you can import it into your desired component:
import { UserContext } '../../App'
function Home() {
const user = useContext(UserContext);
return (
<>
<label>Your name:</label>
<input type='text' onChange={e => user.setName(e.target.value)} />
<p>{user.name}</p>
</>
)
}
It might be because singleProduct.productName was undefiend in initial and get value later so you can simply set that in useEffect like this:
const { getProductsById, singleProduct } = useContext(ProductsContext);
const [productName, setProductName] = useState();
useEffect(() => {
if(singleProduct.productName){
setProductName(singleProduct.productName)
}
},[singleProduct])

How can I send the state (useState) of one file component to another file's component?

REACT.js:
Let say I have a home page with a search bar, and the search bar is a separate component file i'm calling.
The search bar file contains the useState, set to whatever the user selects. How do I pull that state from the search bar and give it to the original home page that
SearchBar is called in?
The SearchBar Code might look something like this..
import React, { useEffect, useState } from 'react'
import {DropdownButton, Dropdown} from 'react-bootstrap';
import axios from 'axios';
const StateSearch = () =>{
const [states, setStates] = useState([])
const [ stateChoice, setStateChoice] = useState("")
useEffect (()=>{
getStates();
},[])
const getStates = async () => {
let response = await axios.get('/states')
setStates(response.data)
}
const populateDropdown = () => {
return states.map((s)=>{
return (
<Dropdown.Item as="button" value={s.name}>{s.name}</Dropdown.Item>
)
})
}
const handleSubmit = (value) => {
setStateChoice(value);
}
return (
<div>
<DropdownButton
onClick={(e) => handleSubmit(e.target.value)}
id="state-dropdown-menu"
title="States"
>
{populateDropdown()}
</DropdownButton>
</div>
)
}
export default StateSearch;
and the home page looks like this
import React, { useContext, useState } from 'react'
import RenderJson from '../components/RenderJson';
import StateSearch from '../components/StateSearch';
import { AuthContext } from '../providers/AuthProvider';
const Home = () => {
const [stateChoice, setStateChoice] = useState('')
const auth = useContext(AuthContext)
console.log(stateChoice)
return(
<div>
<h1>Welcome!</h1>
<h2> Hey there! Glad to see you. Please login to save a route to your prefered locations, or use the finder below to search for your State</h2>
<StateSearch stateChoice={stateChoice} />
</div>
)
};
export default Home;
As you can see, these are two separate files, how do i send the selection the user makes on the search bar as props to the original home page? (or send the state, either one)
You just need to pass one callback into your child.
Homepage
<StateSearch stateChoice={stateChoice} sendSearchResult={value => {
// Your Selected value
}} />
Search bar
const StateSearch = ({ sendSearchResult }) => {
..... // Remaining Code
const handleSubmit = (value) => {
setStateChoice(value);
sendSearchResult(value);
}
You can lift the state up with function you pass via props.
const Home = () => {
const getChoice = (choice) => {
console.log(choice);
}
return <StateSearch stateChoice={stateChoice} giveChoice={getChoice} />
}
const StateSearch = (props) => {
const handleSubmit = (value) => {
props.giveChoice(value);
}
// Remaining code ...
}
Actually there is no need to have stateChoice state in StateSearch component if you are just sending the value up.
Hello and welcome to StackOverflow. I'd recommend using the below structure for an autocomplete search bar. There should be a stateless autocomplete UI component. It should be wrapped into a container that handles the search logic. And finally, pass the value to its parent when the user selects one.
// import { useState, useEffect } from 'react' --> with babel import
const { useState, useEffect } = React // --> with inline script tag
// Autocomplete.jsx
const Autocomplete = ({ onSearch, searchValue, onSelect, suggestionList }) => {
return (
<div>
<input
placeholder="Search!"
value={searchValue}
onChange={({target: { value }}) => onSearch(value)}
/>
<select
value="DEFAULT"
disabled={!suggestionList.length}
onChange={({target: {value}}) => onSelect(value)}
>
<option value="DEFAULT" disabled>Select!</option>
{suggestionList.map(({ id, value }) => (
<option key={id} value={value}>{value}</option>
))}
</select>
</div>
)
}
// SearchBarContainer.jsx
const SearchBarContainer = ({ onSelect }) => {
const [searchValue, setSearchValue] = useState('')
const [suggestionList, setSuggestionList] = useState([])
useEffect(() => {
if (searchValue) {
// some async logic that fetches suggestions based on the search value
setSuggestionList([
{ id: 1, value: `${searchValue} foo` },
{ id: 2, value: `${searchValue} bar` },
])
}
}, [searchValue, setSuggestionList])
return (
<Autocomplete
onSearch={setSearchValue}
searchValue={searchValue}
onSelect={onSelect}
suggestionList={suggestionList}
/>
)
}
// Home.jsx
const Home = ({ children }) => {
const [result, setResult] = useState('')
return (
<div>
<SearchBarContainer onSelect={setResult} />
result: {result}
</div>
)
}
ReactDOM.render(<Home />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Just pass a setState to component
parent component:
const [state, setState] = useState({
selectedItem: ''
})
<StateSearch state={state} setState={setState} />
change parent state from child component:
const StateSearch = ({ state, setState }) => {
const handleStateChange = (args) => setState({…state, selectedItem:args})
return (...
<button onClick={() => handleStateChange("myItem")}/>
...)
}

setState is not a function in react native

I am learning react native, have been getting this error setState is not a function in react native
I searched a lot but nothing was helpful enough.
I have created this simplified code to show the issue
import React, { useState } from "react";
import { Text, View, Button } from "react-native";
const Test = ({ Test1 }) => {
return (
<Button
onPress={() => {
Test1.setState(true);
}}
/>
);
};
const Test1 = () => {
const [state, setState] = useState(false);
if (state) {
return <Text>Test Working</Text>;
} else {
return <Text>Test Not Working</Text>;
}
};
const App = () => {
return (
<View>
<Test Test1={Test1} />
</View>
);
};
export default App;
this is the error: TypeError: Test1.setState is not a function
Please help me fix this.
States can be transferred to other component only as props. You need to call the Test1 component from the App and the Test component from the Test1, then you can pass the props to the Test from Test1. By this you don't need to move the state to other component. you can not pass any component as props and access state or methods from there. You can try this code:
import React, { useState } from "react";
import { Text, View, Button } from "react-native";
const Test = ({ setState}) => {
return (
<Button
onPress={() => {
setState(true);
}}
/>
);
};
const Test1 = () => {
const [state, setState] = useState(false);
if (state) {
return <Text>Test Working</Text>;
} else {
return <Test setState={setState} />;
}
};
const App = () => {
return (
<View>
<Test1 />
</View>
);
};
export default App;
import React, { useState } from "react";
import { Text, View, Button } from "react-native";
const Test = ({ setState }) => {
return (
<Button
onPress={() => {
setState(true);
}}
);
};
const Test1 = ({state}) => {
if (state) {
return <Text>Test Working</Text>;
} else {
return <Text>Test Not Working</Text>;
}
};
const App = () => {
const [state, setState] = useState(false);
return (
<View>
<Test1 state={state} />
<Test setState={setState} />
</View>
);
};
export default App;
There are two problems here.
Your Test1 component is not being used at all
Hooks, and local functions in general, may not be called outside of the component that they are declared on
If you want to manage some local state in your Test component, it needs to live in that component.

Why does the component not re-render after callback?

Given the following two components, I expect the EntryList component to re-render after the state changes in the handleEnttryDelete after the button in EntryForm is clicked. Currently the state changes, but the UI isn't updating itself:
import React, { useState } from "react";
import Button from "#material-ui/core/Button";
import { render } from "#testing-library/react";
const EntryList = (props) => {
const [entryList, setEntryList] = useState(props.data);
const handleEntryDelete = (entry) => {
const newState = entryList.filter(function (el) {
return el._id != entry._id;
});
setEntryList(() => newState);
};
return (
<div>
{entryList.map((entry) => {
return (
<EntryForm entry={entry} handleEntryDelete={handleEntryDelete} />
);
})}
</div>
);
};
const EntryForm = (props) => {
const [entry, setEntry] = useState(props.entry);
return (
<div>
<Button onClick={() => props.handleEntryDelete(entry)}>
{entry._id}
</Button>
</div>
);
};
export default EntryList;
Your code probably works, but not as intended. You just have to use key while mapping arrays to components.
Therefore, React can distinguish which elements should not be touched during reconciliation when you delete one of the nodes
<div>
{entryList.map((entry) => {
return <EntryForm key={entry._id} entry={entry} handleEntryDelete={handleEntryDelete} />;
})}
</div>;

How do access a value from Context.Consumer with recompose?

Im passing some data with React Context API
and I try to access it from inside a recompose methods
In what way do you access Consumer's data with recompose?
import React from "react";
import { MyContext } from "./index";
import { fromRenderProps, withProps, compose } from "recompose";
const enhance = compose(
/**
* #todo add 'Mr.' to each name
*/
withProps(/** How do I get "names" from Consumer here? */)
);
const GrandChild = props => {
return (
<MyContext.Consumer>
{names => {
console.log(names)
return (
<div>
<h2>GrandChild</h2>
{names.map((name, index) => (<li key={index}>{name}</li>))}
</div>
);
}}
</MyContext.Consumer>
);
};
export default enhance(GrandChild);
live code:
https://codesandbox.io/s/k0xm2vlw8r
Here is one way to solve this:
GrandChild.js
import React from "react";
import { MyContext } from "./index";
import { withProps, compose } from "recompose";
const enhance = compose(
withProps(({ names }) => ({ reshapedNames: ["this first", ...names] }))
);
const GrandChild = props => {
return (
<div>
<h2>GrandChild</h2>
{props.reshapedNames.map((name, index) => (
<li key={index}>{name}</li>
))}
</div>
);
};
const EnhancedGrandChild = enhance(GrandChild);
const EnhancedGrandChildWithContext = props => {
return (
<MyContext.Consumer>
{names => <EnhancedGrandChild names={names} {...props} />}
</MyContext.Consumer>
);
};
export default EnhancedGrandChildWithContext;
Just adds a separate layer to provide the context.
Here's the CodeSandbox:

Categories

Resources