How can I set HTML code inside select <option> in React? - reactjs

I'm trying to output pretty fractions inside my options, ¼ ½ ¾ but it's displaying the "&frac 14;" as strings.
How can I get the JSX to interpret my optionContent and render the HTML, not as a string?
optionValue = "4.25"
optionContent = "4 ¾"
{optionContent}

You can do it using the html-react-parser;
Example:
https://codesandbox.io/s/parsing-html-react-zlmwj
import React, { useState } from "react";
import Parser from "html-react-parser";
import "./styles.css";
export default function App() {
const [options, setOption] = useState(1);
const [listOptions] = useState([
{ id: 1, desc: "4 ¼" },
{ id: 2, desc: "4 ½" },
{ id: 3, desc: "4 ¾" }
]);
function handleSelect(e) {
const selected = e.target.value;
setOption(selected);
}
return (
<div className="App">
<h1>Example parsing html in React</h1>
<select value={options} onChange={e => handleSelect(e)}>
{listOptions.map(option => (
<option key={option.id} value={option.id}>
{Parser(option.desc)}
</option>
))}
</select>
</div>
);
}

Related

how to set onChange handler to change the language in react i18next

-the select form that allow the user to change the language don't work with onclick how can I use onChange handler
am using react i18next.
*keep in mind that am not getting any errors or warnings.
this is my code
import i18n from 'i18next';
export default function Footer() {
const languages = [
{
code: "fr",
name: "francais",
countryCode:"fr"
},
{
code: "en",
name: "english",
countryCode:"gb"
},
{
code: "ar",
name: "العربية",
countryCode:"sa"
}
]
return <Form.Select aria-label="Default select example" >
{languages.map(({code,name, countryCode})=>{
return(
<option key={countryCode} onClick={()=> i18n.changeLanguage(code)}>{name}</option>
)
})}
</Form.Select>
}
The onChange handler to change the language needs to be set on the Form.Select component, like this: https://codesandbox.io/s/react-code-works-on-mozilla-but-but-dont-on-chrome-forked-1lkvw?file=/src/Footer.js:579-657
import { useTranslation } from "react-i18next";
import { Container, Form } from "react-bootstrap";
export default function Footer() {
const { i18n } = useTranslation();
const languages = [
{
code: "fr",
name: "francais",
countryCode: "fr"
},
{
code: "en",
name: "english",
countryCode: "gb"
},
{
code: "ar",
name: "العربية",
countryCode: "sa"
}
];
return (
<div className="section footer">
<Container>
<Form.Select
defaultValue={i18n.resolvedLanguage}
onChange={e => {
i18n.changeLanguage(e.target.value);
}}
>
{languages.map(({ code, name, countryCode }) => {
return (
<option
key={countryCode}
value={code}
>
{name}
</option>
);
})}
</Form.Select>
</Container>
</div>
);
}

The optimal way for creating wizard-like form in React

I am creating a wizard-like form in React. I want it to display another select only when user selects an option in a previous dropdown. Currently my selection works, but I am using a lot of useState hooks here. As eventually I want to have around 10 selects, I think that as much as 10 useStates may not be the best option.
Can you please check out my code and give me some tips that would make it better/explain why such change would make it better?
Below I post my code, it works in codesandbox with bootstrap 4.2.1 and react-select 2.2.0:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select from "react-select";
import "./styles.css";
import "bootstrap/dist/css/bootstrap.css";
const options1 = [
{ label: "1", value: 1 },
{ label: "2", value: 2 }
];
const options2 = [
{ label: "3", value: 3 },
{ label: "4", value: 4 }
];
const options3 = [
{ label: "5", value: 5 },
{ label: "6", value: 6 }
];
const options4 = [
{ label: "7", value: 7 },
{ label: "8", value: 8 }
];
const App = () => {
const [showSecond, setShowSecond] = useState(false);
const [showThird, setShowThird] = useState(false);
const [showFourth, setShowFourth] = useState(false);
const [showButton, setShowButton] = useState(false);
const renderSecond = () => {
if (showSecond) {
return (
<div className="form-group row mt-2">
<label className="col-4">Select 2</label>
<Select
onInputChange={updateSecond}
className="col-8"
options={options2}
/>
</div>
);
}
};
const renderThird = () => {
if (showThird) {
return (
<div className="form-group row mt-2">
<label className="col-4">Select 3</label>
<Select
onInputChange={updateThird}
className="col-8"
options={options3}
/>
</div>
);
}
};
const renderFourth = () => {
if (showFourth) {
return (
<div className="form-group row mt-2">
<label className="col-4">Select 4</label>
<Select
onInputChange={updateFourth}
className="col-8"
options={options4}
/>
</div>
);
}
};
const updateFirst = () => {
// update some data
setShowSecond(true);
};
const updateSecond = () => {
// update some data
setShowThird(true);
};
const updateThird = () => {
// update some data
setShowFourth(true);
};
const updateFourth = () => {
// update some data
setShowButton(true);
};
return (
<div className="container">
<div className="col-12">
<form className="form">
<div className="form-group row mt-2">
<label className="col-4">Select 1 </label>
<Select
className="col-8"
onInputChange={updateFirst}
options={options1}
/>
</div>
{renderSecond()}
{renderThird()}
{renderFourth()}
</form>
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
As I am learning React, every suggestion will be very appreciated!

A method triggers a console.log from another component

When I click on bet now the function triggers a console.log from another component. betNow should group all the inputs from stake in one common array but when I click on it it renders the console log from stake and includes all the values that I typed into one array. Everything works but not as I wish. The parent component should display the common array with all the values. I do not understand why it is happening.Could anyone explain me why is reacting like that? Thanks in advance
Parent Component
import React, { useState } from 'react';
import Button from '#material-ui/core/Button';
import FilterMenu from "./selectButton";
import FetchRandomBet from "./fetchRandomBets";
function Betslip() {
const data = [
{
value: 0,
label: "No Filter"
},
{
value: 1,
label: "Less than two"
},
{
value: 2,
label: "More than two"
},
]
const [selectedValue, setSelectedValue] = useState(0);
const [allStakes, setAllStakes] = useState([]);
const handleChange = obj => {
setSelectedValue(obj.value);
}
const betNow = () => {
const stakes = localStorage.getItem("stakes");
const jsnStake = JSON.parse(stakes) || [];
setAllStakes([...allStakes, jsnStake]);
}
return (
<div className="betslip">
<div className="betslip-top">
<h1 className="text">BETSLIP</h1>
<p className="text-two">BET WITH US!</p>
<div>
<FilterMenu
optionsProp={data}
valueProp={selectedValue}
onChangeProp={handleChange}
/>
</div>
</div>
<div>
<FetchRandomBet
valueProp={selectedValue}
/>
</div>
<Button
onClick={betNow}
className="betnow"
variant="contained"
>
Bet Now!
</Button>
</div>
);
}
export default Betslip;
Child Component
import React, { useState, useEffect } from 'react';
function Stake() {
const [stakes, setStakes] = useState([]);
const addStake = (e) => {
e.preventDefault();
const newStake = e.target.stake.value;
setStakes([newStake]);
};
useEffect(() => {
const json = JSON.stringify(stakes);
localStorage.setItem("stakes", json);
}, [stakes]);
console.log(stakes)
return (
<div>
<form onSubmit={addStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
/>
</form>
</div>
);
}
export default Stake;
You have this console.log in you function that will run every time the component is rendered, since it´s outside of any function:

Cascade Dropdown using react Hooks

Hi Guys I'm new to React. I am trying to create a cascade drop down list using react hooks and the way I did it works well but I feel something wrong in the way I did it. Please check this code and tell me there is a way that I can improve my code.Thanks in advance
import React, { useState } from 'react';
import './App.css';
function App() {
const[data, setName] = useState({
countrie:"",
state:""
});
let state;
const countrie =['Germany','India','France']
const gstate = ['Duesseldorf', 'Leinfelden-Echterdingen', 'Eschborn']
const istate = ['Delhi', 'Kolkata', 'Mumbai', 'Bangalore']
const fstate =['Auvergne','Bretagne','Corse','Centre']
if(data.countrie==="Germany"){
state = gstate.map((gstate,key)=> <option key={key} value={gstate}>{gstate}</option>)
}else if(data.countrie==="India"){
state = istate.map((istate,key)=> <option key={key} value={istate}>{istate}</option>)
}else{
state = fstate.map((fstate,key)=> <option key={key} value={fstate}>{fstate}</option>)
}
const countries = countrie.map((countrie,key)=> <option key={key} value={countrie}>{countrie}</option>)
function handleCountry(e){
setName({...data,countrie:e.target.value});
}
function handleStateChange(e){
setName({...data,state:e.target.value});
}
return (
<form onSubmit={handleSubmit}>
<div>
<select value={data.countrie} onChange={handleCountry}>
{countries}
</select>
</div>
<div>
<select value={data.state} onChange={handleStateChange}>
{state}
</select>
</div>
<input type="submit" />
</form>
);
}
export default App;
The best suggestion I have is to change the data structure which combines the country and states. Doing so makes it a lot easier to map over each country and getting the states without having to map variables. This makes it also more scalable.
Here is an example using the country data as a collection:
Codesandbox
import React, { useState } from "react";
const countriesData = [
{
name: "Germany",
states: ["Duesseldorf", "Leinfelden-Echterdingen", "Eschborn"]
},
{
name: "India",
states: ["Delhi", "Kolkata", "Mumbai", "Bangalore"]
},
{
name: "France",
states: ["Auvergne", "Bretagne", "Corse", "Centre"]
}
];
function Form() {
const [{ country, state }, setData] = useState({
country: "Germany",
state: ""
});
const countries = countriesData.map((country) => (
<option key={country.name} value={country.name}>
{country.name}
</option>
));
const states = countriesData.find(item => item.name === country)?.states.map((state) => (
<option key={state} value={state}>
{state}
</option>
));
function handleCountryChange(event) {
setData(data => ({ state: '', country: event.target.value }));
}
function handleStateChange(event) {
setData(data => ({ ...data, state: event.target.value }));
}
return (
<form onSubmit={() => console.log("Submitted")}>
<div>
<select value={country} onChange={handleCountryChange}>
{countries}
</select>
</div>
<div>
<select value={state} onChange={handleStateChange}>
{states}
</select>
</div>
<input type="submit" />
</form>
);
}
export default Form;

Set title onSubmit based on current SELECT OPTION VALUE - react

I found this tutorial on how to create a react quizz app on youtube link to tutorial
I am trying to set the title based on the current Select Option Value when submitting the form.
Currently I managed to change the title only when a different option is selected.
import React, { useState, useEffect, useRef } from "react";
import "./App.css";
import axios from "axios";
import FlashcardList from "./components/FlashcardList";
function App() {
const [flashcards, setFlashcards] = useState([]);
const [categories, setCategories] = useState([]);
const [title, setTitle] = useState("General Knowledge");
const categoryEl = useRef();
const amountEl = useRef();
useEffect(() => {
axios.get("https://opentdb.com/api_category.php").then((res) => {
setCategories(res.data.trivia_categories);
});
}, []);
function decodeString(str) {
const textArea = document.createElement("textarea");
textArea.innerHTML = str;
return textArea.value;
}
function handleSubmit(e) {
e.preventDefault();
axios
.get("https://opentdb.com/api.php", {
params: {
amount: amountEl.current.value,
category: categoryEl.current.value,
},
})
.then((res) => {
setFlashcards(
res.data.results.map((questionItem, index) => {
const answer = decodeString(questionItem.correct_answer);
const options = [...questionItem.incorrect_answers, answer];
return {
id: `${index} - ${Date.now()}`,
question: decodeString(questionItem.question),
answer: answer,
options: options.sort(() => Math.random() - 0.5),
};
})
);
});
}
function getTitle(e) {
setTitle(e.target.options[e.target.selectedIndex].text);
}
return (
<>
<form className="header" onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="category">Category</label>
<select id="category" ref={categoryEl} onChange={getTitle}>
{categories.map((category) => {
return (
<option value={category.id} key={category.id}>
{category.name}
</option>
);
})}
</select>
</div>
<div className="form-group">
<label htmlFor="amount">Number Of Questions</label>
<input
type="number"
id="amount"
min="1"
step="1"
defaultValue={10}
ref={amountEl}
/>
</div>
<div className="form-group">
<button className="btn">Generate</button>
</div>
</form>
<div className="container">
<h1 className="title">{title}</h1>
<FlashcardList flashcards={flashcards} />
</div>
</>
);
}
export default App;
Code
Live demo
You can set the category as soon the categories are fetched. Can just use the zeroth element to set the title.
useEffect(() => { axios.get("https://opentdb.com/api_category.php").then((res) => {
setCategories(res.data.trivia_categories);
setTitle(res.data.trivia_categories[0]);
});
}, []);

Resources