I'm reading a book about React, but it's out of date and it's from React16. The book is Progressive Web Apps. I managed to update most of the things to React19, but I can't pass methods by reference like it's done in the book. From what I've seen, React removed 'refs' and is using useRef or createRef, but I'm not able to do it according to the book.
This is the reference by refs through react16
import React from 'react';
import './App.css';
import Header from './components/Header/Header.tsx';
import NovoUsuario from './components/NovoUsuário/NovoUsuario.tsx';
import Toast from './components/Toast/Toast.tsx'
function App() {
return (
<div>
<Header />
<NovoUsuario erro={msg => this.refs.toast.erro(msg)} />
<Toast />
</div>
);
}
export default App;
pass method by reference = this.refs.toast.erro(msg) i pass ref in toast but in this is undefined, refs is not found. from what i saw refs was deprecated and replaced by react hooks after 16 onwards like useRef but I couldn't use useRef Context and others
The erro() component comes from the NovoUsuario class which is inside the validate(e) function.
import React from 'react'
import Label from '../Label/Label.tsx'
import Input from '../Input/Input.tsx'
import GenderSelector from '../GenderSelector/GenderSelector.tsx'
import Usuario from '../../models/Usuario.ts'
import Button from '../Button/Button.tsx'
class NovoUsuario extends React.Component <any, any> {
constructor(props){
super(props)
this.state = {
usuario: new Usuario(),
validacao: {
nomeInvalido: false,
generoInvalido: false
},
primeiraVisaoCompleta: false
}
}
validar(e) {
e.preventDefault()
let usuario = this.state.usuario
let validacao = this.state.validacao
validacao.nomeInvalido = ! usuario.validarNome()
validacao.generoInvalido = ! usuario.validarGenero()
let mensagem = ''
let primeiraVisaoCompleta = false
if(validacao.nomeInvalido && validacao.generoInvalido) {
mensagem = 'Os campos nome e gênero estão inválidos!'
} else if (validacao.nomeInvalido) {
mensagem = 'Seu nome está inválido!'
} else if (validacao.generoInvalido) {
mensagem = 'Selecione seu gênero!'
} else {
primeiraVisaoCompleta = true
}
if (!primeiraVisaoCompleta) {
this.props.erro(mensagem)
}
this.setState({
validacao: validacao,
primeiraVisaoCompleta: primeiraVisaoCompleta
})
}
atualizarNome(e) {
let usuario = this.state.usuario
usuario.nome = e.target.value
this.setState({
usuario: usuario
})
}
atualizarGenero(e, genero) {
e.preventDefault()
let usuario = this.state.usuario
usuario.genero = genero
this.setState({
usuario: usuario
})
}
renderizarNome() {
return(
<section>
<Label
for="nome"
texto="Quem é você?"
valorInvalido={this.state.validacao.nomeInvalido}
/>
<Input
id="nome"
placeholder="Digite seu nome"
maxLength="40"
readOnly={this.state.primeiraVisaoCompleta}
valorInvalido={this.state.validacao.nomeInvalido}
defaultValue={this.state.usuario.nome}
onChange={this.atualizarNome.bind(this)}
/>
</section>
)
}
renderizarGenero() {
if (this.state.primeiraVisaoCompleta) {
return null
} else {
return(
<section>
<Label
texto="Seu gênero."
valorInvalido={this.state.validacao.generoInvalido}
/>
<GenderSelector
valorInvalido={this.state.validacao.generoInvalido}
genero={this.state.usuario.genero}
atualizarGenero={this.atualizarGenero.bind(this)}
/>
</section>
)
}
}
renderizarBotoes() {
if (this.state.primeiraVisaoCompleta) {
return(
<section>
<Button
texto="Voltar"
onClick={e => {
e.preventDefault()
this.setState({
primeiraVisaoCompleta: false
})
}}
/>
<Button
principal
texto="Salvar"
/>
</section>
)
} else {
return(
<section>
<Button
principal
texto="Próximo"
onClick={this.validar.bind(this)}
/>
</section>
)
}
}
render() {
return(
<div className="center">
<form className="pure-form pure-form-stacked">
{this.renderizarNome()}
{this.renderizarGenero()}
{this.renderizarBotoes()}
</form>
</div>
)
}
}
export default NovoUsuario
I tried using ref useRef useContext and it didn't work, what would be the easiest way to access the function by reference in another component?
this is the component Toast
import React, { createContext } from "react"
import { ToastContainer, toast } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
class Toast extends React.Component <any, any> {
sucesso = (msg) => {
toast.success(msg)
}
info = (msg) => {
toast.info(msg)
}
erro = (msg) => {
toast.error(msg)
}
render() {
return(
<ToastContainer
position="bottom-center"
autoClose={5000}
hideProgressBar={true}
closeOnClick
pauseOnHover
/>
)
}
}
export default Toast
the logic that operates the props goes from NovoUsuario > app > toast where erro, sucesso and info will be responsible for using react-toastify, but the error message is sent by NovoUsuario in the validate(e) method, when I run the application everything works, except if the fields are empty "Cannot find refs in ..."
React function components are "instance-less", so this
is simply undefined.
The App
component just needs to create a React ref to pass to the Toast
component such that its ref value is available within App
to pass down to other components or to be used in callbacks.
Example:
function App() {
// (1) Create ref object
const toastRef = React.useRef(null);
return (
<div>
<Header />
{/* (3) use ref in callback function, access current ref value */}
<NovoUsuario erro={msg => toastRef.current?.erro(msg)} />
{/* (2) pass ref */}
<Toast ref={toastRef} />
</div>
);
}