I cannot wrap my head around how to pass the value of a selected radio button to another component in React. I'm fiddeling around with the Star Wars API at the moment. Trying to build a simple OPA where the user can fetch information about characters and places in the SW universe.
The user is able to choose which type of information he wants, e.g. searching for planets and then input the name and other information of the chosen planet.
I am trying to build this functionality with a combination of radio buttons and a text input.
I put the text input and the radio buttons in two distinct components - how do I get them to communicate with each other - or to put in another way:
How can I pass the value of one radio button to the other component which adds it to the URL I want to fetch?
My code for the radio button component:
import { React, useState } from 'react';
import styled from 'styled-components';
import {
FormControl,
FormControlLabel,
RadioGroup,
Radio,
} from '@material-ui/core';
const ChooseOption = () => {
const [selected, setSelected] = useState('films');
const isButtonSelected = (value) => {
if (selected === value) {
return true;
}
};
const handleChange = (e) => {
setSelected(e.target.value);
};
return (
<Container>
<FormControl component="fieldset">
<RadioGroup
className="radio-group"
row
aria-label="star wars ressource"
name="row-radio-buttons-group"
value={selected}
>
<FormControlLabel
value="films"
control={<Radio />}
label="Films"
checked={isButtonSelected('films')}
onChange={handleChange}
/>
<FormControlLabel
value="people"
control={<Radio />}
label="People"
checked={isButtonSelected('people')}
onChange={handleChange}
/>
<FormControlLabel
value="planets"
control={<Radio />}
label="Planets"
checked={isButtonSelected('planets')}
onChange={handleChange}
/>
<FormControlLabel
value="species"
control={<Radio />}
label="Species"
checked={isButtonSelected('species')}
onChange={handleChange}
/>
<FormControlLabel
value="starships"
control={<Radio />}
label="Starships"
checked={isButtonSelected('starships')}
onChange={handleChange}
/>
<FormControlLabel
value="vehicles"
control={<Radio />}
label="Vehicles"
checked={isButtonSelected('vehicles')}
onChange={handleChange}
/>
</RadioGroup>
</FormControl>
</Container>
);
};
export default ChooseOption;
const Container = styled.div`
text-align: center;
.radio-group {
width: 85%;
margin: auto;
color: white;
}
.MuiFormControlLabel-root {
display: grid;
margin: 1rem 1.5rem;
.MuiButtonBase-root {
background-color: #000;
}
}
`;
My Code for the form component which consists of the radio button component and the text input:
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import { baseURL, appendix, routeObject } from '../api';
import { Button } from '@material-ui/core';
import ChooseOption from './ChooseOption';
const SearchItem = () => {
const [search, setSearch] = useState('');
const [selected, setSelected] = useState();
const [data, setData] = useState([]);
const handleChange = (e) => {
setSearch(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
};
const handleRadio = (e) => {
setSelected(e.target.value);
console.log(selected);
};
// const searchForRessource = () => {
// fetch(baseURL search)
// .then((response) => {
// return response.json();
// })
// .then((data) => console.log(data));
// };
useEffect(() => {
fetch(baseURL)
.then((response) => {
return response.json();
})
.then((data) => setData(data));
}, []);
console.log(data);
return (
<>
<Container>
<form className="input-form" onSubmit={handleSubmit}>
<ChooseOption onChange={handleRadio} />
<input
className="text-input"
type="text"
id="item-input"
onChange={handleChange}
value={search}
/>
</form>
<Button>Search</Button>
</Container>
</>
);
};
export default SearchItem;
const Container = styled.div`
.input-form {
margin: 2rem auto;
text-align: center;
.text-input {
background-color: var(--starWarsYellow);
width: 70%;
border: none;
padding: 0.75rem;
color: #000;
border-radius: 3px;
}
.text-input:focus {
outline: none;
}
}
.MuiButtonBase-root {
background-color: var(--starWarsYellow);
width: 45%;
display: block;
margin: auto;
}
.MuiButtonBase-root:active {
background-color: green;
}
`;
CodePudding user response:
You're passing an onChange handler to your ChooseOption
component but are never calling it. You can either hold the state of the radio button inside your SearchItem
component (as you already have a state object for it (selected), or you can add a useEffect hook inside ChooseOption
that calls onChange every time your selected
state is updated inside there (or better yet in your handleChange
function:
import { React, useState } from 'react';
import styled from 'styled-components';
import {
FormControl,
FormControlLabel,
RadioGroup,
Radio,
} from '@material-ui/core';
const ChooseOption = ({ onChange }) => { // define the passed onChange handler
const [selected, setSelected] = useState('films');
const isButtonSelected = (value) => {
if (selected === value) {
return true;
}
};
const handleChange = (e) => {
setSelected(e.target.value);
onChange(e); // this fires the onChange handler (handleRadio) you passed in SearchItem
};
return (
<Container>
<FormControl component="fieldset">
<RadioGroup
className="radio-group"
row
aria-label="star wars ressource"
name="row-radio-buttons-group"
value={selected}
>
<FormControlLabel
value="films"
control={<Radio />}
label="Films"
checked={isButtonSelected('films')}
onChange={handleChange}
/>
<FormControlLabel
value="people"
control={<Radio />}
label="People"
checked={isButtonSelected('people')}
onChange={handleChange}
/>
<FormControlLabel
value="planets"
control={<Radio />}
label="Planets"
checked={isButtonSelected('planets')}
onChange={handleChange}
/>
<FormControlLabel
value="species"
control={<Radio />}
label="Species"
checked={isButtonSelected('species')}
onChange={handleChange}
/>
<FormControlLabel
value="starships"
control={<Radio />}
label="Starships"
checked={isButtonSelected('starships')}
onChange={handleChange}
/>
<FormControlLabel
value="vehicles"
control={<Radio />}
label="Vehicles"
checked={isButtonSelected('vehicles')}
onChange={handleChange}
/>
</RadioGroup>
</FormControl>
</Container>
);
};
export default ChooseOption;
const Container = styled.div`
text-align: center;
.radio-group {
width: 85%;
margin: auto;
color: white;
}
.MuiFormControlLabel-root {
display: grid;
margin: 1rem 1.5rem;
.MuiButtonBase-root {
background-color: #000;
}
}
`;
Holding your state of the radio buttons in 2 places might be a bit confusing, so consider moving the state management entirely inside SearchItem