function component vs function - the sense of using function components - reactjs

My problem is I do not really understand if using function components instead function is good idea in below example:
first program without function components
class App extends React.Component {
state = {
check: false,
isFormSubmitted: false
}
handleChangeChecked = () => {
this.setState({
check: !this.state.check,
isFormSubmitted: false
})
return (true)
}
displayMsg = () => {
if (this.state.isFormSubmitted == true) {
if (this.state.check == true)
return (<p>You are allowed to watch this film!</p>)
else return (<p>You are not allowed to watch this film.</p>)
} else return (null)
}
handleFormSubmit = (e) => {
e.preventDefault()
this.setState({
isFormSubmitted: true
})
}
render() {
return (
<React.Fragment>
<h1>Film</h1>
<form onSubmit={this.handleFormSubmit}>
<input type="checkbox" onChange={this.handleChangeChecked} checked={this.state.check} />
<label>I have got 16 years old</label>
<button>Buy ticket</button>
</form>
{this.displayMsg()}
</React.Fragment>
)
}
}
ReactDOM.render(< App />, document.getElementById('root'));
second program with function components:
const PositiveMessage = () => <p>Mozesz obejrzeć film, zapraszam</p>;
const NegativeMessage = () => <p>Nie możesz obejrzeć tego filmu !</p>;
class TicketShop extends React.Component {
state = {
isConfirmed: false,
isFormSubmitted: false
}
handleCheckboxChange = () => {
this.setState({
isConfirmed: !this.state.isConfirmed,
isFormSubmitted: false
})
}
displayMessage = () => {
if (this.state.isFormSubmitted) {
if (this.state.isConfirmed) { return <PositiveMessage /> }
else { return <NegativeMessage /> }
} else { return null }
}
handleFormSubmit = (e) => {
e.preventDefault()
if (!this.state.isFormSubmitted) {
this.setState({
isFormSubmitted: !this.state.isFormSubmitted
})
}
}
render() {
return (
<>
<h1>Kup bilet na horror roku !</h1>
<form onSubmit={this.handleFormSubmit}>
<input type="checkbox" id="age" onChange={this.handleCheckboxChange} checked={this.state.isConfirmed} />
<label htmlFor="age">Mam conajmniej 16 lat</label>
<br />
<button type="submit">Kup bilet</button>
</form>
{this.displayMessage()}
</>
)
}
}
ReactDOM.render(<TicketShop />, document.getElementById('root'))
i made two programs with and without function components and i dont see the difference of working.
In user point of view both programs works without any difference.

Related

TestDont - Change Username - REACT

Looking for thinking tips towards refactoring the App function. The component must remain unchanged. This example is clunky and a mashup of several different online contributions to the use of ref.
I started here: https://reactjs.org/docs/refs-and-the-dom.html
Thanks in advance.
class Username extends React.Component {
state = { value: "" };
changeValue(value) {
this.setState({ value });
}
render() {
const { value } = this.state;
return <h1>{value}</h1>;
}
}
function App() {
this.username = React.useRef();
this.component = React.useRef()
clickHandler = e => {
//console.log(this.component.current.changeValue())
this.component.current.changeValue(this.username.current.value)
}
return (
<div>
<button onClick={clickHandler}>Change Username</button>
<input type="text" ref={this.username}/>
<Username ref={this.component}/>
</div>
);
}
document.body.innerHTML = "<div id='root'></div>";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
document.querySelector("input").value = "John Doe";
document.querySelector("button").click();
setTimeout(() => console.log(document.getElementById("root").innerHTML));
Try this code.
function Username({ value }) {
return (
<h1>{value}</h1>
);
}
class App extends React.Component {
state = {
usernameDynamic: '',
usernameStatic: '',
}
onChangeUserName = () => {
this.setState({ usernameStatic: usernameDynamic });
}
onChangeUserNameDynamic = (e) => {
this.setState({ usernameDynamic: e.target.value });
}
render() {
return (
<div>
<button onClick={this.onChangeUserNameStatic}>Change Username</button>
<input type="text" value={this.state.usernameDynamic} onChange={this.onChangeUserNameDynamic} />
<Username value={this.state.usernameStatic} />
</div>
);
}
}

React context: send input data to another component

I have 3 components:
Search.js, Customers.js and Customer.js
In Search.js I have an input field. I want to send whatever value entered in the field over to the Customer.js component. I thought this would be straightforward, but I was wrong ...
I have also a context.js component that stores state for the application (I don't want to use redux because I don't know it yet).
Sorry but this is gonna be a long post as I want to give the background for this specific situation:
context.js
const Context = React.createContext();
const reducer = (state, action) => {
switch (action.type) {
case "SEARCH_CUSTOMERS":
return {
...state,
customer_list: action.payload,
firstName: ''
};
default:
return state;
}
};
export class Provider extends Component {
state = {
customer_list: [],
firstName: "",
dispatch: action => this.setState(state => reducer(state, action))
};
componentDidMount() {
axios
.get("/api")
.then(res => {
console.log(res.data);
this.setState({ customer_list: res.data });
})
.catch(error => console.log(error));
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
Search.js: the input value I want to send to Customer is 'firstName'
class Search extends Component {
state = {
firstName: ""
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
findCustomer = (dispatch, e) => {
e.preventDefault();
axios
.get("/api/customers", {
params: {
firstName: this.state.firstName,
}
})
.then(res => {
dispatch({
type: "SEARCH_CUSTOMERS",
payload: res.data
});
this.setState({ firstName: "" });
});
};
return (
<Consumer>
{value => {
const { dispatch } = value;
return (
<form onSubmit={this.findCustomer.bind(this, dispatch)}>
<div className="form-group">
<input
ref={input => {
this.nameInput = input;
}}
type="text"
name="firstName"
value={this.state.firstName}
onChange={this.onChange}
/>
the Customers.js:
class Customers extends Component {
render() {
const key = Date.now();
return (
<Consumer>
{value => {
const { customer_list} = value;
if (customer_list === undefined || customer_list.length === 0) {
return <Spinner />;
} else {
return (
<React.Fragment>
<h3 className="text-center mb-4">{heading}</h3>
<div className="row">
{customer_list.map(item => (
<Customer key={item.key} customer={item} />
))}
</div>
</React.Fragment>
);
}
}}
</Consumer>
);
}
}
export default Customers;
and Finally theCustomer.js: this is where I want the input value to be displayed:
const Customer = props => {
const { customer } = props;
return (
<div className="col-md-12">
<div className="card-body">
<strong>{customer.firstName}</strong> // not working
...
}
the {customer.firstName} does not show the value.
Is is necessary to go through the intermediate Customers.js component to pass the input value?
I would like to keep the architecture as is (with the context.js) and display the value in the Customer.js component.

React function not returning <div> element

In the following code:
class App extends React.Component {
state = { val: '' };
handleChange = (e) => {
this.setState({ val: e.target.value });
}
OddEven(num) {
const number = parseInt(num);
let description;
if (Number.isInteger(number)) {
if (number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
alert(number);
return (
<h1>
Test
</h1>
);
} else {
return null;
}
}
render() {
return (
<div>
<input type='text' onChange={this.handleChange} />
<button onClick={() =>this.OddEven(this.state.val) }>
Odd Even
</button>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
the OddEven() is not returning the div. Can't figure out why for the last 2 hours. I'm in the learning phase. So don't get offended if it's something silly.
if you want to return your description here is how to do it:
class App extends React.Component {
state = {
val: '',
description: null,
};
handleChange = (e) => {
this.setState({ val: e.target.value });
}
OddEven(num) {
const number = parseInt(num);
let {description} = this.state;
if (Number.isInteger(number)) {
if (number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
this.setState({description: description});
} else {
this.setState({description: null});
}
}
render() {
return (
<div>
<input type='text' onChange={this.handleChange} />
<button onClick={() =>this.OddEven(this.state.val) }>
Odd Even Check?
</button>
{this.state.description}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
That is because you are not rendering what your function returns anywhere, what you would rather want to do is this:
class App extends React.Component {
state = { val: "", oddeven: "" }
handleChange = e => {
this.setState({ val: e.target.value })
}
OddEven = () => {
const number = parseInt(this.state.val) //Use the state directly
let description
if (Number.isInteger(number)) {
if (number % 2 == 0) {
description = <strong>even</strong>
} else {
description = <i>odd</i>
}
alert(number)
this.setState({ oddEven: "Hello" })
} else {
return null
}
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<button onClick={this.OddEven}>Odd Even</button> {/* you do not need to passs the state here, you can directly access it in your function */}
{this.state.oddEven && <h1>{this.state.oddEven}</h1>} {/* Here we check if oddEven exists and then we display whatever we set in the OddEven function}
</div>
)
}
}
Here we set the state to what you want to render and then use that inside our render function.
Try This :
class App extends React.Component {
state = { val: '' };
handleChange = (e) => {
this.setState({ val: e.target.value });
}
OddEven(num) {
const number = parseInt(num);
if (Number.isInteger(number)) {
if (number % 2 == 0) {
return <strong>even</strong>;
} else {
return <i>odd</i>;
}
} else {
return <a>Please Enter A Number</a>;
}
}
render() {
return (
<div>
<input type='text' onChange={this.handleChange} />
{OddEven(this.state.val)}
</div>
);
}

Determine clicked item and update aria-checked value in React

render(){
return (
<div>
this.data.map(item=> {
<div aria-checked="true/false">{item}<div>
})
</div>
)
}
For the above code, I want to write an onClick handler that changes the value of aria-checked to true, depending on the item selected/clicked on. If one item is selected, it's aria-checked will be true and the rest false.
I know I need a checked component state with a boolean type but I'm not sure how to do the handler logic.
you can do by setAttribute, here:
constructor() {
super();
this.data = ["hello", "world"];
}
handleClick = (e) => {
const currentAriaChecked = (e.currentTarget.getAttribute("aria-checked") === 'true');
e.currentTarget.setAttribute("aria-checked", !currentAriaChecked);
};
render() {
return (
<div>
{
this.data
.map(item => (<div aria-checked="true" onClick={this.handleClick}>{item}</div>))
}
</div>
);
}
UPDATE
using typescript and react way
render() {
return (
<div>
{
this.data
.map(item => (<Check>{item}</Check>))
}
</div>
);
}
your component check
state = {
isChecked: false
}
handleClick = (e) => {
this.setState((prevState,props) => {
return {isChecked: !prevState.isChecked }
})
};
render() {
return (
<div aria-checked={this.state.isChecked} onClick={this.handleClick}>
{this.props.children} {this.state.isChecked.toString()}
</div>
);
}
see playground.

React/Jest How to test function outside of the class component

So in the example below i have validateResult which is set to the displayMessage. Depending on the user input it'd return a value, this is outside of the class component and i dont know how to test a function outside of the class with jest.
So i tried using mount from enzyme to mount the component then with instance to access the function but this gave me an error saying that this is not a function and im not sure how to test this.
test.js
const wrapper = mount (
<tempComponent />,
);
const instance = wrapper.instance();
it('expect result to be good', () => {
expect(instance.validateResult(true)).toBe("good");
});
tempComponent.js
const validateResult = (data) => {
if(data)
return "good";
else
return "bad";
};
class tempComponent extends Component {
constructor(props) {
super(props);
this.state = { inputdata: '' };
this.onSuccess = this.onSuccess.bind(this);
}
render() {
const { inputdata } = this.state;
const { onSubmit } = this.props;
const displayMessage = validateResult(inputdata);
return (
<div id="submit-form" className="row justify-content-center">
<div className="col-md-4">
<FormContainer onSubmit={() => onSubmit({ inputdata }, this.onSuccess)} >
<Input type="text" label="" onTextChange={(value) => this.setState({ ...this.state, inputdata: value })} text={inputdata} />
<SubmitButton value={'Submit'} disabled={displayMessage}/>
</FormContainer>
</div>
</div>
);
}
}

Resources